如何用Fuse.js实现忽略位置的精确匹配?
解决Fuse.js严格搜索匹配不符合预期的问题
问题分析
你开启严格搜索(threshold: 0)后,Fuse.js仍然匹配中间包含额外字符/内容的结果,本质是默认配置下Fuse会对搜索词和目标文本做分词匹配,忽略了短语的连续性。要实现「搜索短语必须连续完整出现在目标字段中」的效果,可通过以下方案解决:
方案一:利用扩展搜索语法实现精确短语匹配(推荐)
结合你已开启的useExtendedSearch: true,在调用搜索时给严格模式下的关键词包裹双引号,Fuse会自动匹配连续完整的短语:
// 假设searchTerm是用户输入的搜索关键词 const searchResults = fuse.search(isStrictSearch ? `"${searchTerm}"` : searchTerm);
保持原有Fuse配置不变即可,这种方式直接利用Fuse原生功能,无需复杂配置:
- 搜索
"Maki Sticks 1kg"时,只会匹配包含连续子串Maki Sticks 1kg的条目,原数据中的Surimi Maki Sticks - 1kg因中间有-不会被匹配 - 搜索
"No Worries Can"时,原数据中的No Worries Wild Berry Can因中间有Wild Berry不会被匹配
方案二:自定义匹配逻辑
如果不想依赖搜索语法,可通过matcher自定义字段匹配规则,严格模式下直接检查搜索词是否为目标字段的连续子串:
const fuse = useMemo(() => { return new Fuse<Fees>(data, { includeMatches: true, keys: [{ name: "name", matcher: (searchTerm, value) => { if (isStrictSearch) { // 严格模式:检查搜索词是否是目标文本的连续子串 return value.includes(searchTerm); } // 非严格模式使用Fuse默认匹配逻辑 return Fuse.defaultMatcher(searchTerm, value); } }], ignoreLocation: !isStrictSearch, useExtendedSearch: true, threshold: isStrictSearch ? 0 : 0.6, }); }, [data, isStrictSearch]);
注意:自定义matcher可能会影响includeMatches返回的匹配详情,若需保留完整匹配信息,可结合Fuse内部方法调整。
方案三:调整原生配置实现连续token匹配
若希望通过纯配置实现,可开启分词并限制token的连续匹配:
const fuse = useMemo(() => { const baseOptions = { includeMatches: true, keys: [{ name: "name" }], useExtendedSearch: true, }; const strictOptions = { threshold: 0, ignoreLocation: false, distance: 0, // 强制token之间无间隔 matchAllTokens: true, // 必须匹配所有搜索token tokenize: true, tokenizer: (str) => str.split(/\W+/).filter(Boolean), // 按非字母数字字符分词 }; const looseOptions = { threshold: 0.6, ignoreLocation: true, }; return new Fuse<Fees>(data, { ...baseOptions, ...(isStrictSearch ? strictOptions : looseOptions), }); }, [data, isStrictSearch]);
这种配置会要求搜索的所有token在目标文本中连续出现,适用于以分词为基础的严格匹配场景。
内容的提问来源于stack exchange,提问作者Owenn
相关产品推荐
相关产品推荐

