ReactJS中如何按命中类型配置ElasticSearch搜索排序
完全可以实现你要的自定义排序规则,你之前用的多字段加权重写法是multi_match的简化配置,只能区分字段维度的权重,没法区分不同匹配类型的得分差异,核心解决方案是用bool组合多类匹配子句,给每个「字段+匹配类型」的组合设置固定权重,按ES内置得分倒排即可。
先匹配你的优先级规则做权重映射
ES的得分计算规则是命中的子句权重累加,得分越高排序越靠前。你给出的优先级数值越小优先级越高,因此反向给高优先级规则设置更高的boost值即可,只要保证高优先级的boost值大于所有低优先级规则的boost值总和,就不会出现得分倒挂:
| 字段\匹配类型 | Full-Hit(全匹配) | Start-hit(前缀匹配) | Sub-hit(子串匹配) | Fuzzy-hit(模糊匹配) |
|---|---|---|---|---|
| category(分类) | 优先级1 → boost=120 | 优先级3 → boost=100 | 优先级5 → boost=80 | 优先级10 → boost=30 |
| trade name(商品名) | 优先级2 → boost=110 | 优先级4 → boost=90 | 优先级6 → boost=70 | 优先级11 → boost=20 |
| official name(通用名) | 优先级7 → boost=60 | 优先级8 → boost=50 | 优先级9 → boost=40 | 优先级12 → boost=10 |
各匹配类型的对应ES实现
你对四类匹配的定义基本准确,不需要调整,对应ES的原生查询能力就能完全覆盖你的示例规则:
- Full-hit:用
match_phrase查询,slop设为0,要求搜索词分词后按顺序连续匹配,刚好满足「John匹配John doe、不匹配JohnDoe」的规则 - Start-hit:用
match_phrase_prefix查询,匹配以搜索词为开头的短语,刚好满足「John匹配Johndoe、Doe不匹配JohnDoe」的规则 - Sub-hit:不要用通配符查询(性能极差),提前给字段配置
ngram分词子字段,生成连续字符的分词索引,设置分词有效字符仅包含字母、数字,遇到空格/分隔符自动断词,刚好满足「baker匹配breadbakeries、不匹配de backer」的规则 - Fuzzy-hit:用带fuzziness参数的
match查询,fuzziness设为1(对应编辑距离为1的单字符增/删/改/相邻交换场景),prefix_length设为2,刚好满足「bakker匹配baker、不匹配bakers」的规则
React侧对接实现
React本身不影响ES查询逻辑,不管你是用官方@elastic/elasticsearch客户端还是直接发HTTP请求,只要把下面构造的查询体传给ES的_search接口即可:
const keyword = "用户输入的搜索词"; const searchBody = { query: { bool: { should: [ // category 字段匹配规则 { match_phrase: { category: { query: keyword, boost: 120 } } }, { match_phrase_prefix: { category: { query: keyword, boost: 100, max_expansions: 50 } } }, { match: { "category.ngram": { query: keyword, boost: 80 } } }, { match: { category: { query: keyword, fuzziness: "1", prefix_length: 2, boost: 30 } } }, // trade name 字段(替换成你实际的字段名,比如你之前用的name) { match_phrase: { name: { query: keyword, boost: 110 } } }, { match_phrase_prefix: { name: { query: keyword, boost: 90, max_expansions: 50 } } }, { match: { "name.ngram": { query: keyword, boost: 70 } } }, { match: { name: { query: keyword, fuzziness: "1", prefix_length: 2, boost: 20 } } }, // official name 字段匹配规则 { match_phrase: { "official name": { query: keyword, boost: 60 } } }, { match_phrase_prefix: { "official name": { query: keyword, boost: 50, max_expansions: 50 } } }, { match: { "official name.ngram": { query: keyword, boost: 40 } } }, { match: { "official name": { query: keyword, fuzziness: "1", prefix_length: 2, boost: 10 } } } ], minimum_should_match: 1 } } }
前置配置注意事项
- 子串匹配依赖的
ngram子字段需要在创建索引时提前配置映射,min_gram设为2、max_gram按业务最长搜索词长度调整(一般设为10即可),不要用动态映射默认生成的字段。 - 如果测试时出现低优先级结果排在前面的得分倒挂问题,直接把高优先级规则的boost值调高(比如把category全匹配的boost调到1000),保证单条高优先级命中的得分超过所有低优先级规则的得分总和即可。
- 前缀匹配的
max_expansions参数不要设太大,控制在50以内可以避免查询性能下降。
内容的提问来源于stack exchange,提问作者Yorbjörn
相关产品推荐
相关产品推荐

