Elastic中实现部分搜索的正确索引方案与查询选型
结论先行
全首尾带通配符的wildcard查询绝对不适合放到线上实时检索链路,纯默认的autocomplete筛选器也满足不了你提的中间片段匹配需求,最优方案是按字段特性自定义分词映射,别硬套现成的筛选器
先厘清两个筛选器的适用边界,避开选型误区
很多人选型的时候只看功能名字,没搞清楚底层逻辑,上来就踩坑:
- 为啥全包裹通配符的
wildcard不能用?
你之前从官方文档看到的性能问题一点不夸张:这种*DEF*的查询,本质是对所有匹配字段做逐行的字符串扫描,没有倒排索引可以走,尤其是你存的ID、postal_code一般都是keyword类型,本身没有做切分,数据量到百万级的时候,单查询延迟能冲到几百毫秒,甚至会把线程池打满,线上根本扛不住 - 为啥标准
autocomplete筛选器也满足不了需求?
这个筛选器本质是对字符串做从开头逐段截断的切分,比如存ABCDEFGH的话,切出来的token是A、AB、ABC、ABCD……根本不会切出DEF这个片段,你搜DEF的时候完全召不回结果,根本实现不了你要的“从长ID中间找片段”的能力
按字段特性做定制化映射,完全匹配需求且性能拉满
你现在的三个字段,其实需求特性可以分成两类,分开配置就行,不需要一套逻辑适配所有:
1. ID、reference_id类需要支持任意中间片段匹配的长字符串字段
配合ngram分词器做自定义字段映射,原理是索引阶段就把字符串按固定长度切成所有可能的片段,检索的时候直接命中倒排索引,根本不需要扫描:
// 索引配置 { "analysis": { "analyzer": { "id_partial_analyzer": { "tokenizer": "id_ngram_tokenizer" } }, "tokenizer": { "id_ngram_tokenizer": { "type": "ngram", "min_gram": 3, "max_gram": 10, "token_chars": ["letter", "digit"] } } }, "mappings": { "properties": { "id": { "type": "keyword", "fields": { "partial": { "type": "text", "analyzer": "id_partial_analyzer", "search_analyzer": "standard" } } } } } }
这个配置的实际效果:
- 存储值为ABCDEFGH时,会被切成3位长度的片段ABC、BCD、CDE、DEF、EFG、FGH,你输入DEF检索的时候,直接命中对应倒排token,查询延迟和普通term查询差不多,比带通配符的wildcard快两个数量级
- 注意
min_gram别设成1或者2,不然会导致倒排索引体积翻好几倍,设成3刚好匹配用户一般输3个以上字符才触发检索的交互习惯,max_gram设10足够覆盖日常的检索词长度
2. postal_code类需要支持前缀层级匹配的短数字字段
配合edge_ngram分词器做映射就行,不需要上重量级的ngram,因为这类字段本身就是短字符串,切分逻辑更简单:
{ "analysis": { "tokenizer": { "postal_edge_tokenizer": { "type": "edge_ngram", "min_gram": 1, "max_gram": 5, "token_chars": ["digit"] } } }, "mappings": { "properties": { "postal_code": { "type": "keyword", "fields": { "prefix": { "type": "text", "analyzer": "edge_ngram_analyzer" } } } } } }
这个配置的实际效果完全匹配你的需求:
- 存储值为29019时,切出来的token是2、29、290、2901、29019
- 存储值为27829时,切出来的token是2、27、278、2782、27829
- 输入检索词“2”时,两个存储值都有"2"这个token,能同时召回;输入检索词“29”时,只有29019有对应token,精准匹配召回
选型决策参考
- 只有当你需要做纯前缀补全(比如输入"ela"补全成"elasticsearch")、不需要中间片段匹配的时候,才考虑用现成的
autocomplete筛选器,它本质就是封装好的edge_ngram,灵活度不如自己配置分词 - 只有做离线排查、查询频率极低的时候,才用
wildcard筛选器,绝对不要放到用户实时检索的链路里 - 上面提到的自定义ngram/edge_ngram方案,常规数据量下单查询延迟可以控制在10ms以内,同场景下比全包裹通配符的wildcard查询性能高50-100倍,完全能支撑线上检索需求
内容的提问来源于stack exchange,提问作者nanakondor
相关产品推荐
相关产品推荐

