From a75a28f5c45e38b9053400c3fecd0fbcdff35fbb Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Mon, 10 May 2021 13:03:22 +0200 Subject: [PATCH] Fixing benchmark (Adding new search cases after advanced search is ready) --- benchmark/BenchmarkRunner.ts | 116 ++++++++++++++++++++++++-- benchmark/index.ts | 2 +- src/backend/middlewares/GalleryMWs.ts | 10 +-- test/common/unit/SearchQueryParser.ts | 54 ++++++------ 4 files changed, 140 insertions(+), 42 deletions(-) diff --git a/benchmark/BenchmarkRunner.ts b/benchmark/BenchmarkRunner.ts index bad57edc..1b6c69f2 100644 --- a/benchmark/BenchmarkRunner.ts +++ b/benchmark/BenchmarkRunner.ts @@ -19,8 +19,17 @@ import {PersonManager} from '../src/backend/model/database/sql/PersonManager'; import {GalleryRouter} from '../src/backend/routes/GalleryRouter'; import {Express} from 'express'; import {PersonRouter} from '../src/backend/routes/PersonRouter'; -import {QueryParams} from '../src/common/QueryParams'; -import {SearchQueryTypes, TextSearch} from '../src/common/entities/SearchQueryDTO'; +import { + ANDSearchQuery, + ORSearchQuery, + SearchQueryDTO, + SearchQueryTypes, + SomeOfSearchQuery, + TextSearch, + TextSearchQueryMatchTypes, + TextSearchQueryTypes +} from '../src/common/entities/SearchQueryDTO'; +import {QueryKeywords, SearchQueryParser} from '../src/common/SearchQueryParser'; export interface BenchmarkResult { @@ -124,18 +133,107 @@ export class BenchmarkRunner { return await bm.run(this.RUNS); } - async bmAllSearch(text: string): Promise<{ result: BenchmarkResult, searchType: SearchQueryTypes }[]> { + async bmAllSearch(): Promise<{ result: BenchmarkResult, searchQuery: SearchQueryDTO }[]> { await this.setupDB(); - const types = Utils.enumToArray(SearchQueryTypes).map((a): number => a.key).concat([null]); - const results: { result: BenchmarkResult, searchType: SearchQueryTypes }[] = []; - for (const type of types) { + const queryKeywords: QueryKeywords = { + NSomeOf: '-of', + and: 'and', + caption: 'caption', + directory: 'directory', + file_name: 'file-name', + from: 'from', + keyword: 'keyword', + landscape: 'landscape', + maxRating: 'max-rating', + maxResolution: 'max-resolution', + minRating: 'min-rating', + minResolution: 'min-resolution', + or: 'or', + orientation: 'orientation', + person: 'person', + portrait: 'portrait', + position: 'position', + someOf: 'some-of', + to: 'to', + kmFrom: 'km-from' + }; + const queryParser = new SearchQueryParser(queryKeywords); + const names = (await ObjectManagers.getInstance().PersonManager.getAll()).sort((a, b) => b.count - a.count); + const queries: { query: SearchQueryDTO, description: string }[] = TextSearchQueryTypes.map(t => { + const q = { + type: t, text: 'a' + }; + return { + query: q, description: queryParser.stringify(q) + }; + }); + // searching for everything + queries.push({ + query: { + type: SearchQueryTypes.any_text, text: '.' + } as TextSearch, description: queryParser.stringify({ + type: SearchQueryTypes.any_text, text: '.' + } as TextSearch) + }); + if (names.length > 0) { + queries.push({ + query: { + type: SearchQueryTypes.person, text: names[0].name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch, description: '' + }); + } + if (names.length > 1) { + queries.push({ + query: { + type: SearchQueryTypes.AND, list: [ + { + type: SearchQueryTypes.person, text: names[0].name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch, + { + type: SearchQueryTypes.person, text: names[1].name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch + ] + } as ANDSearchQuery, description: '' + }); + queries.push({ + query: { + type: SearchQueryTypes.OR, list: [ + { + type: SearchQueryTypes.person, text: names[0].name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch, + { + type: SearchQueryTypes.person, text: names[1].name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch + ] + } as ORSearchQuery, description: '' + }); + queries.push({ + query: { + type: SearchQueryTypes.SOME_OF, + min: 2, + list: names.map(n => ({ + type: SearchQueryTypes.person, text: n.name, + matchType: TextSearchQueryMatchTypes.exact_match + } as TextSearch)) + } as SomeOfSearchQuery, description: '' + }); + } + const results: { result: BenchmarkResult, searchQuery: SearchQueryDTO }[] = []; + + for (const entry of queries) { const req = Utils.clone(this.requestTemplate); - req.query[QueryParams.gallery.search.query] = ({type, text} as TextSearch); - const bm = new Benchmark('Searching for `' + text + '` as `' + (type ? SearchQueryTypes[type] : 'any') + '`', req); + req.params.searchQueryDTO = JSON.stringify(entry.query); + + const bm = new Benchmark('Searching for `' + entry.description + '`', req); BMGalleryRouter.addSearch(bm.BmExpressApp); - results.push({result: await bm.run(this.RUNS), searchType: type}); + results.push({result: await bm.run(this.RUNS), searchQuery: entry.query}); } return results; } diff --git a/benchmark/index.ts b/benchmark/index.ts index 8b50ed77..db48d66d 100644 --- a/benchmark/index.ts +++ b/benchmark/index.ts @@ -70,7 +70,7 @@ const run = async () => { printResult(await bm.bmSaveDirectory()); printResult(await bm.bmListDirectory()); printResult(await bm.bmListPersons()); - (await bm.bmAllSearch('a')).forEach(res => printResult(res.result)); + (await bm.bmAllSearch()).forEach(res => printResult(res.result)); printResult(await bm.bmAutocomplete('a')); printLine('*Measurements run ' + RUNS + ' times and an average was calculated.'); console.log(resultsText); diff --git a/src/backend/middlewares/GalleryMWs.ts b/src/backend/middlewares/GalleryMWs.ts index 0df59155..623e8c23 100644 --- a/src/backend/middlewares/GalleryMWs.ts +++ b/src/backend/middlewares/GalleryMWs.ts @@ -9,7 +9,7 @@ import {ContentWrapper} from '../../common/entities/ConentWrapper'; import {PhotoDTO} from '../../common/entities/PhotoDTO'; import {ProjectPath} from '../ProjectPath'; import {Config} from '../../common/config/private/Config'; -import {UserDTO, UserDTOUtils} from '../../common/entities/UserDTO'; +import {UserDTOUtils} from '../../common/entities/UserDTO'; import {MediaDTO, MediaDTOUtils} from '../../common/entities/MediaDTO'; import {VideoDTO} from '../../common/entities/VideoDTO'; import {Utils} from '../../common/Utils'; @@ -79,11 +79,11 @@ export class GalleryMWs { store: true, // disable compression }); - res.on('close', function() { + res.on('close', () => { console.log('zip ' + archive.pointer() + ' bytes'); }); - archive.on('error', function(err: any) { + archive.on('error', (err: any) => { throw err; }); @@ -92,12 +92,12 @@ export class GalleryMWs { // append photos in absoluteDirectoryName // using case-insensitive glob of extensions for (const ext of SupportedFormats.WithDots.Photos) { - archive.glob(`*${ext}`, {cwd:absoluteDirectoryName, nocase:true}); + archive.glob(`*${ext}`, {cwd: absoluteDirectoryName, nocase: true}); } // append videos in absoluteDirectoryName // using case-insensitive glob of extensions for (const ext of SupportedFormats.WithDots.Videos) { - archive.glob(`*${ext}`, {cwd:absoluteDirectoryName, nocase:true}); + archive.glob(`*${ext}`, {cwd: absoluteDirectoryName, nocase: true}); } await archive.finalize(); diff --git a/test/common/unit/SearchQueryParser.ts b/test/common/unit/SearchQueryParser.ts index 154e47b6..89277060 100644 --- a/test/common/unit/SearchQueryParser.ts +++ b/test/common/unit/SearchQueryParser.ts @@ -19,33 +19,33 @@ import { } from '../../../src/common/entities/SearchQueryDTO'; import {QueryKeywords, SearchQueryParser} from '../../../src/common/SearchQueryParser'; +const queryKeywords: QueryKeywords = { + NSomeOf: '-of', + and: 'and', + caption: 'caption', + directory: 'directory', + file_name: 'file-name', + from: 'from', + keyword: 'keyword', + landscape: 'landscape', + maxRating: 'max-rating', + maxResolution: 'max-resolution', + minRating: 'min-rating', + minResolution: 'min-resolution', + or: 'or', + orientation: 'orientation', + person: 'person', + portrait: 'portrait', + position: 'position', + someOf: 'some-of', + to: 'to', + kmFrom: 'km-from' +}; + describe('SearchQueryParser', () => { - const keywords: QueryKeywords = { - NSomeOf: '-of', - and: 'and', - caption: 'caption', - directory: 'directory', - file_name: 'file-name', - from: 'from', - keyword: 'keyword', - landscape: 'landscape', - maxRating: 'max-rating', - maxResolution: 'max-resolution', - minRating: 'min-rating', - minResolution: 'min-resolution', - or: 'or', - orientation: 'orientation', - person: 'person', - portrait: 'portrait', - position: 'position', - someOf: 'some-of', - to: 'to', - kmFrom: 'km-from' - }; - const check = (query: SearchQueryDTO) => { - const parser = new SearchQueryParser(keywords); + const parser = new SearchQueryParser(queryKeywords); expect(parser.parse(parser.stringify(query))).to.deep.equals(query, parser.stringify(query)); }; @@ -72,14 +72,14 @@ describe('SearchQueryParser', () => { check({type: SearchQueryTypes.to_date, value: (new Date(2020, 1, 20)).getTime()} as ToDateSearch); check({type: SearchQueryTypes.to_date, value: (new Date(2020, 1, 1)).getTime()} as ToDateSearch); - const parser = new SearchQueryParser(keywords); + const parser = new SearchQueryParser(queryKeywords); // test if date gets simplified on 1st of Jan. let query: RangeSearch = {type: SearchQueryTypes.to_date, value: (new Date(2020, 0, 1)).getTime()} as ToDateSearch; - expect(parser.parse(keywords.to + ':' + (new Date(query.value)).getFullYear())) + expect(parser.parse(queryKeywords.to + ':' + (new Date(query.value)).getFullYear())) .to.deep.equals(query, parser.stringify(query)); query = ({type: SearchQueryTypes.from_date, value: (new Date(2020, 0, 1)).getTime()} as FromDateSearch); - expect(parser.parse(keywords.from + ':' + (new Date(query.value)).getFullYear())) + expect(parser.parse(queryKeywords.from + ':' + (new Date(query.value)).getFullYear())) .to.deep.equals(query, parser.stringify(query)); });