Skip to content
Snippets Groups Projects
Commit f953ed72 authored by Etienne LOUPIAS's avatar Etienne LOUPIAS
Browse files

Merge branch 'feat/US29-search-improvement' into 'dev'

feat/US29-search-improvement

See merge request web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server!112
parents 541d6290 fbbf2fb6
No related branches found
No related tags found
3 merge requests!1251.14,!1171.13,!112feat/US29-search-improvement
......@@ -37,11 +37,15 @@ deploy_dev:
test:
stage: test
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/node:14.15.4
services:
- name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/elasticsearch:7.16.2
alias: elasticsearch
command: ['bin/elasticsearch', '-Expack.security.enabled=false', '-Ediscovery.type=single-node']
before_script:
- export GHOST_HOST_AND_PORT=http://localhost:2368
- export GHOST_ADMIN_API_KEY=60142bc9e33940000156bccc:6217742e2671e322612e89cac9bab61fcd01822709fe5d8f5e6a5b3e54d5e6bb
- export SALT=$TEST_SALT
- export ELASTICSEARCH_NODE=http://localhost:9200
- export ELASTICSEARCH_NODE=http://elasticsearch:9200
script:
- npm i
- npm run test:cov
......
......@@ -3,6 +3,7 @@ import { StructureSearchBody } from './structure-search-body.interface';
export interface StructureSearchResult {
hits: {
total: number;
max_score: number;
hits: Array<{
_score: number;
_source: StructureSearchBody;
......
......@@ -44,6 +44,7 @@ describe('StructuresService', () => {
}).compile();
service = module.get<StructuresService>(StructuresService);
service['structuresSearchService']['index'] = 'structures-unit-test';
});
it('should be defined', () => {
......
import { Logger } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { StructuresForSearchServiceMock } from '../../../test/mock/services/structures-for-search.mock.service';
import { MailerModule } from '../../mailer/mailer.module';
import { SearchModule } from '../../search/search.module';
import { StructuresSearchService } from './structures-search.service';
import { StructuresService } from './structures.service';
describe('StructuresSearchService', () => {
let service: StructuresSearchService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [MailerModule, SearchModule, ConfigModule],
providers: [
StructuresSearchService,
{
provide: StructuresService,
useClass: StructuresForSearchServiceMock,
},
],
}).compile();
service = module.get<StructuresSearchService>(StructuresSearchService);
service['index'] = 'structures-unit-test';
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should create index', async () => {
await service.dropIndex();
const res = await service.createStructureIndex();
expect(res).toBeTruthy();
});
it('should index structures', async () => {
const structuresForSearchService = new StructuresForSearchServiceMock();
const structures = structuresForSearchService.findAll();
const res = await Promise.all(
structures.map((structure: any) => {
service.indexStructure(structure);
})
);
expect(res).toBeTruthy();
// wait for the new structures to be indexed before search
await service.refreshIndexStructure();
// but we still need to wait the refresh to be done
await new Promise((r) => setTimeout(r, 1000));
});
it('should find maisons de la métropole', async () => {
const res = await service.search('maison de la');
//Logger.log(JSON.stringify(res));
expect(res[0].structureName).toContain('Maison de la Métropole');
expect(res[1].structureName).toContain('Maison de la Métropole');
});
it('should find metropole', async () => {
const res = await service.search('metropole');
expect(res[0].structureName).toContain('Métropole');
});
it('should find text in description', async () => {
const res = await service.search('liseuse');
expect(res.length).toBe(1);
expect(res[0].structureName).toContain("Médiathèque d'Ecully");
});
it('should drop index', async () => {
const res = await service.dropIndex();
expect(res).toBeTruthy();
});
});
......@@ -29,6 +29,20 @@ export class StructuresSearchService {
public async createStructureIndex(): Promise<any> {
return this.elasticsearchService.indices.create({
index: this.index,
body: {
settings: {
analysis: {
analyzer: {
default: {
type: 'french',
},
default_search: {
type: 'french',
},
},
},
},
},
});
}
......@@ -54,6 +68,12 @@ export class StructuresSearchService {
return structure;
}
public async refreshIndexStructure(): Promise<any> {
return this.elasticsearchService.indices.refresh({
index: this.index,
});
}
public async search(searchString: string): Promise<StructureSearchBody[]> {
searchString = searchString ? searchString + '*' : '*';
const { body } = await this.elasticsearchService.search<StructureSearchResult>({
......@@ -71,14 +91,8 @@ export class StructuresSearchService {
},
},
});
const maxScore = Math.max.apply(
Math,
body.hits.hits.map(function (hit) {
return hit._score;
})
);
const sortedHits = body.hits.hits.filter(function (elem) {
return elem._score >= maxScore / 1.5;
return elem._score >= body.hits.max_score / 1.5;
});
return sortedHits.map((item) => item._source);
}
......
export class StructuresForSearchServiceMock {
findAll() {
return [
{
_id: '607ef197225ffd001391edb9',
structureName: "Médiathèque d'Ecully",
structureType: 'mediatheque',
address: {
numero: '1',
street: 'Avenue Edouard Aynard',
commune: 'Écully',
},
description:
'Nous sommes une équipe de 6 personnes accompagnant les usagers dans leur démarche de découverte des outils numériques, mettant à disposition sous forme de prêt des liseuses et du livre numérique et organisant des ateliers individuels de prise en main des outils numériques et tentant de répondre aux questions des usages sur des sujets divers.',
},
{
_id: '60368194cda3ba42b8e621dd',
structureName: 'Maison des associations (Grézieu-la-Varenne)',
structureType: 'autre',
address: {
numero: null,
street: " Place de l'Abbe Launay",
commune: 'Grézieu-la-Varenne',
},
description: null,
},
{
_id: '60b4b0836a9d4500313b8661',
structureName: 'Mairie (La Tour de Salvagny)',
structureType: 'mairie',
address: {
numero: null,
street: 'Place de la Mairie',
commune: 'La Tour-de-Salvagny',
},
description: null,
},
{
_id: '604b84e914d486001790ee57',
structureName: 'Maison de la Métropole (Ecully)',
structureType: 'mdm',
address: {
numero: '10',
street: 'Chemin Jean-Marie Vianney',
commune: 'Écully',
},
description: null,
},
{
_id: '61977124eb90f20031137c35',
structureName: 'Maison de la Métropole (Oullins)',
structureType: 'mdm',
address: {
numero: '17',
street: 'Rue Tupin',
commune: 'Oullins',
},
description: null,
},
];
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment