From 0a5e9fa7571ce79d0330a22244ec28fa1eacb8c9 Mon Sep 17 00:00:00 2001 From: Luca Ongaro Date: Wed, 22 Nov 2023 14:43:03 +0100 Subject: [PATCH] Add queryTerms to the search results (#241) The `queryTerms` field is useful to know which query terms matched in the search result. When performing an exact search, `terms` and `queryTerms` are identical. In case of prefix or fuzzy match though, they can be different. For example, if one searches for "moto" using prefix search, and a result matches with the word "motorcycle", then for that result the `terms` array will include "motorcycle", while the `queryTerms` array will include "moto". --- src/MiniSearch.test.js | 16 ++++++++++++++++ src/MiniSearch.ts | 16 +++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/MiniSearch.test.js b/src/MiniSearch.test.js index a2c48162..fc01805b 100644 --- a/src/MiniSearch.test.js +++ b/src/MiniSearch.test.js @@ -1349,6 +1349,10 @@ describe('MiniSearch', () => { ['vita', 'nova'], ['vita'] ]) + expect(results.map(({ queryTerms }) => queryTerms)).toEqual([ + ['vita', 'nova'], + ['vita'] + ]) }) it('reports correct info when combining terms with AND', () => { @@ -1359,6 +1363,9 @@ describe('MiniSearch', () => { expect(results.map(({ terms }) => terms)).toEqual([ ['vita', 'nova'] ]) + expect(results.map(({ queryTerms }) => queryTerms)).toEqual([ + ['vita', 'nova'] + ]) }) it('reports correct info for fuzzy and prefix queries', () => { @@ -1371,6 +1378,10 @@ describe('MiniSearch', () => { ['vita', 'nova'], ['vita'] ]) + expect(results.map(({ queryTerms }) => queryTerms)).toEqual([ + ['vi', 'nuova'], + ['vi'] + ]) }) it('reports correct info for many fuzzy and prefix queries', () => { @@ -1385,6 +1396,11 @@ describe('MiniSearch', () => { ['vita', 'mezzo', 'del'], ['del'] ]) + expect(results.map(({ queryTerms }) => queryTerms)).toEqual([ + ['vi', 'nuova', 'm', 'de'], + ['vi', 'm', 'de'], + ['de'] + ]) }) it('passes only the query to tokenize', () => { diff --git a/src/MiniSearch.ts b/src/MiniSearch.ts index 49633520..6ecbfff7 100644 --- a/src/MiniSearch.ts +++ b/src/MiniSearch.ts @@ -288,10 +288,17 @@ export type SearchResult = { id: any, /** - * List of terms that matched + * List of document terms that matched. For example, if a prefix search for + * `"moto"` matches `"motorcycle"`, `terms` will contain `"motorcycle"`. */ terms: string[], + /** + * List of query terms that matched. For example, if a prefix search for + * `"moto"` matches `"motorcycle"`, `queryTerms` will contain `"moto"`. + */ + queryTerms: string[], + /** * Score of the search results */ @@ -1229,14 +1236,17 @@ export default class MiniSearch { const results = [] for (const [docId, { score, terms, match }] of rawResults) { - // Final score takes into account the number of matching QUERY terms. - // The end user will only receive the MATCHED terms. + // terms are the matched query terms, which will be returned to the user + // as queryTerms. The quality is calculated based on them, as opposed to + // the matched terms in the document (which can be different due to + // prefix and fuzzy match) const quality = terms.length || 1 const result = { id: this._documentIds.get(docId), score: score * quality, terms: Object.keys(match), + queryTerms: terms, match }