Skip to content

Commit 62bda5e

Browse files
committed
fix(search): compare query and ticket words by the same singular key in the Jira floor
Rebuilding plural forms from a word's key missed singular words whose plural adds -es (release, database, license): their key drops the final e, so neither the word nor its plural was found and the floor dropped valid partial matches. Both sides now go through the same key, as an analyzer does for query and document, with a term containing punctuation matched as written.
1 parent 3ccdd16 commit 62bda5e

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

‎apps/sim/lib/sim-search/live/term-fallback.test.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,34 @@ describe('searchWithAnyTermFallback', () => {
250250
expect(result.documents.map((document) => document.id)).toEqual(['plurals'])
251251
})
252252

253+
it('counts a singular word whose plural adds -es, in either form', async () => {
254+
const search = provider(
255+
page(),
256+
page(
257+
{ id: 'singular', title: 'Database release' },
258+
{ id: 'plural', title: 'Databases', content: 'Weekly releases' }
259+
)
260+
)
261+
const result = await searchWithAnyTermFallback(
262+
search,
263+
{ query: 'database release checklist owner', limit: 10, scopes: [] },
264+
live,
265+
halfTheTerms
266+
)
267+
expect(result.documents.map((document) => document.id).sort()).toEqual(['plural', 'singular'])
268+
})
269+
270+
it('counts a term with punctuation inside it, such as ci/cd', async () => {
271+
const search = provider(page(), page({ id: 'ci', title: 'CI/CD pipeline' }))
272+
const result = await searchWithAnyTermFallback(
273+
search,
274+
{ query: 'ci/cd pipeline failure owner', limit: 10, scopes: [] },
275+
live,
276+
halfTheTerms
277+
)
278+
expect(result.documents.map((document) => document.id)).toEqual(['ci'])
279+
})
280+
253281
it('returns the all-terms page unchanged when no partial match is close enough', async () => {
254282
const strict = page({ id: 'exact', title: 'Glean token creator role request' })
255283
const search = provider(strict, page({ id: 'loose', title: 'Role request' }))

‎apps/sim/lib/sim-search/live/text-match.ts‎

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,15 @@ export function termCoverage(text: string, terms: readonly string[]): number {
117117
}
118118

119119
/**
120-
* Whether the text holds at least half the query's distinct terms, a word and its regular plural
121-
* counting as one term as a stemmed search matches them.
120+
* Whether the text holds at least half the query's distinct terms. Query and text words are
121+
* compared by their singular key, so a word and its regular plural count as one term as a stemmed
122+
* search matches them; a term with punctuation inside it is matched as written.
122123
*/
123124
export function containsHalfTheTerms(text: string, query: string): boolean {
124-
const terms = distinctTerms(query, singularKey).map(singularKey)
125-
const present = terms.filter((term) => findTermMatches(text, wordForms(term)).length > 0)
125+
const terms = distinctTerms(query, singularKey)
126+
const words = new Set(text.match(/[\p{L}\p{N}_]+/gu)?.map(singularKey))
127+
const present = terms.filter(
128+
(term) => words.has(singularKey(term)) || findTermMatches(text, [term]).length > 0
129+
)
126130
return present.length >= Math.ceil(terms.length / 2)
127131
}
128-
129-
/** A singular word and its regular plural forms, longest first so a plural is matched whole. */
130-
function wordForms(singular: string): string[] {
131-
const forms = [`${singular}es`, `${singular}s`, singular]
132-
return singular.endsWith('y') ? [`${singular.slice(0, -1)}ies`, ...forms] : forms
133-
}

0 commit comments

Comments
 (0)