Skip to content

Commit 646b5a0

Browse files
authored
fix: refine fuzzy matching order (#507)
Ref #504
2 parents 5ca07d6 + 60d2b0b commit 646b5a0

File tree

2 files changed

+74
-27
lines changed

2 files changed

+74
-27
lines changed

docusaurus-search-local/src/client/utils/smartQueries.spec.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ describe("smartQueries with no stop words filter", () => {
260260
});
261261
});
262262

263-
describe("smartQueries with fuzzy matching", () => {
263+
describe("smartQueries with fuzzy matching distance 1", () => {
264264
beforeEach(() => {
265265
__setFuzzyMatchingDistance(1);
266266
});
@@ -307,6 +307,48 @@ describe("smartQueries with fuzzy matching", () => {
307307
});
308308
});
309309

310+
describe("smartQueries with fuzzy matching distance 2", () => {
311+
beforeEach(() => {
312+
__setFuzzyMatchingDistance(2);
313+
});
314+
315+
test.each<[string[], TestQuery[]]>([
316+
[
317+
["a", "hello"],
318+
[
319+
{
320+
tokens: ["a", "hello"],
321+
keyword: "+a +hello",
322+
},
323+
{
324+
tokens: ["a", "hello"],
325+
keyword: "+a +hello*",
326+
},
327+
{
328+
tokens: ["a", "hello"],
329+
keyword: "+a +hello~1",
330+
},
331+
{
332+
tokens: ["a", "hello"],
333+
keyword: "+a +hello*~1",
334+
},
335+
{
336+
tokens: ["a", "hello"],
337+
keyword: "+a +hello~2",
338+
},
339+
{
340+
tokens: ["a", "hello"],
341+
keyword: "+a +hello*~2",
342+
},
343+
],
344+
],
345+
])("smartQueries(%j, zhDictionary) should work", (tokens, queries) => {
346+
expect(smartQueries(tokens, zhDictionary).map(transformQuery)).toEqual(
347+
queries
348+
);
349+
});
350+
});
351+
310352
function transformQuery(query: SmartQuery): TestQuery {
311353
return {
312354
tokens: query.tokens,

docusaurus-search-local/src/client/utils/smartQueries.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -97,58 +97,57 @@ export function smartQueries(
9797
}
9898
}
9999

100-
return getQueriesMaybeTyping(terms).concat(
101-
fuzzyMatchingDistance > 0
102-
? getQueriesMaybeTyping(terms, fuzzyMatchingDistance)
103-
: [],
104-
getQueriesMaybeTyping(extraTerms),
105-
fuzzyMatchingDistance > 0
106-
? getQueriesMaybeTyping(extraTerms, fuzzyMatchingDistance)
107-
: []
100+
const distance = Math.max(0, fuzzyMatchingDistance);
101+
return getDistanceMatrix(terms, distance).concat(
102+
getDistanceMatrix(extraTerms, distance)
108103
);
109104
}
110105

111106
function getQueriesMaybeTyping(
112107
terms: SmartTerm[],
113-
editDistance?: number
108+
editDistance: number
114109
): SmartQuery[] {
115-
return termsToQueries(terms, false, editDistance).concat(
110+
return termsToQueries(terms, editDistance).concat(
116111
termsToQueries(
117112
// Ignore terms whose last token already has a trailing wildcard,
118113
// or the last token is not `maybeTyping`.
119114
terms.filter((term) => {
120115
const token = term[term.length - 1];
121116
return !token.trailing && token.maybeTyping;
122117
}),
123-
true,
124-
editDistance
118+
editDistance,
119+
true
125120
)
126121
);
127122
}
128123

129124
function termsToQueries(
130125
terms: SmartTerm[],
131-
maybeTyping?: boolean,
132-
editDistance?: number
126+
editDistance: number,
127+
maybeTyping?: boolean
133128
): SmartQuery[] {
134129
return terms.flatMap((term) => {
135130
const query = {
136131
tokens: term.map((item) => item.value),
137-
term: term.map((item) => ({
138-
value: item.value,
139-
presence: lunr.Query.presence.REQUIRED,
132+
term: term.map((item) => {
140133
// The last token of a term maybe incomplete while user is typing.
141134
// So append more queries with trailing wildcard added.
142-
wildcard: (
143-
maybeTyping ? item.trailing || item.maybeTyping : item.trailing
144-
)
145-
? lunr.Query.wildcard.TRAILING
146-
: lunr.Query.wildcard.NONE,
147-
editDistance:
148-
editDistance && item.value.length > editDistance
135+
const trailing = maybeTyping
136+
? item.trailing || item.maybeTyping
137+
: item.trailing;
138+
const distance =
139+
editDistance > 0 && item.value.length > editDistance
149140
? editDistance
150-
: undefined,
151-
})),
141+
: undefined;
142+
return {
143+
value: item.value,
144+
presence: lunr.Query.presence.REQUIRED,
145+
wildcard: trailing
146+
? lunr.Query.wildcard.TRAILING
147+
: lunr.Query.wildcard.NONE,
148+
editDistance: distance,
149+
};
150+
}),
152151
};
153152

154153
// Ignore queries that all terms ignored edit distance due to too short tokens.
@@ -159,3 +158,9 @@ function termsToQueries(
159158
return query;
160159
});
161160
}
161+
162+
function getDistanceMatrix(terms: SmartTerm[], distance: number) {
163+
return Array.from({ length: distance + 1 }, (_, i) =>
164+
getQueriesMaybeTyping(terms, i)
165+
).flat();
166+
}

0 commit comments

Comments
 (0)