为何Elastic Search中Edge Ngram版Completion Suggester索引体积增15-17倍?
问题背景
我正在为包含字母数字与冒号的多字段(示例值:AA:890090:xyz:9090)实现Completion Suggester。使用默认的simple分析器时,因为它只对字母分词,没法得到像AA:890这类包含冒号和数字前缀的建议。为了解决这个问题,我改用了Edge Ngram分析器,虽然解决了建议的问题,但索引体积比默认分析器大了15-17倍——默认下约3GB,用了Ngram后直接到50GB。
请问为什么Edge Ngram analyzer的索引体积会这么大?另外我当前的Elasticsearch mapping如下,有没有更优的实现方式?
示例映射:
{ "settings": { "analysis": { "filter": { "ngram_filter": { "type": "edge_ngram", "min_gram": 3, "max_gram": 40 } }, "analyzer": { "ngram_analyzer": { "type": "custom", "tokenizer": "whitespace", "filter": [ "lowercase", "ngram_filter" ] } } } }, "mappings": { "doc": { "properties": { "field1Suggest": { "type": "completion", "analyzer": "ngram_analyzer", "search_analyzer": "whitespace" }, "field2Suggest": { "type": "completion", "analyzer": "ngram_analyzer", "search_analyzer": "whitespace" } } } } }
为什么索引体积会暴增?
咱们先拆解下Edge Ngram分析器的工作逻辑:
- 你的字段值
AA:890090:xyz:9090会被whitespace分词器当成单个完整token(因为没有空格)。 - 接着
edge_ngram过滤器会把这个token拆分成从min_gram=3到max_gram=40的所有前缀子串——比如AA:、AA:8、AA:89、AA:890……一直到完整的字符串。 - 假设你的字段平均长度是18个字符,那每个token会生成
18-3+1=16个不同的ngram。
这些ngram都会被存入Completion Suggester的FST(有限状态机)结构中,百万级别的数据下来,相当于要存储原本15-17倍的内容,索引体积自然就暴增了。
更优的实现方案:放弃Edge Ngram,用原生前缀匹配
其实你之前走进了一个小误区——Completion Suggester本身就原生支持前缀匹配,根本不需要用Edge Ngram来生成额外的子串!
之前用simple分析器不行,是因为它会把你的字段拆成多个独立的token(比如aa、890090、xyz),导致补全候选只能是这些单个token,而不是整个字段。只要我们让completion字段把整个字符串作为单个token存入,就能直接实现前缀补全,同时保持索引体积和原始数据量级一致。
修改后的Mapping示例
推荐使用带小写转换的自定义keyword分析器(支持大小写不敏感匹配):
{ "settings": { "analysis": { "analyzer": { "keyword_lowercase": { "type": "custom", "tokenizer": "keyword", "filter": ["lowercase"] } } } }, "mappings": { "doc": { "properties": { "field1Suggest": { "type": "completion", "analyzer": "keyword_lowercase", "search_analyzer": "keyword_lowercase" }, "field2Suggest": { "type": "completion", "analyzer": "keyword_lowercase", "search_analyzer": "keyword_lowercase" } } } } }
方案优势
- 索引体积回归正常:整个字段作为单个token存入,不会生成额外的ngram,体积会和你之前用simple分析器的3GB量级接近。
- 满足前缀补全需求:用户输入
AA:890或aa:890时,都能匹配到AA:890090:xyz:9090这类完整字段。 - 性能更优:FST结构更小,搜索时的匹配速度也会更快。
特殊场景补充
如果你的业务需要支持中间段的前缀匹配(比如输入890要匹配所有包含890开头子段的字段),可以考虑配置Multi-field:一个字段用keyword分析器做整段前缀补全,另一个字段用ngram分析器做模糊匹配,但这种情况要权衡索引体积和业务需求——不过根据你的问题描述,整段前缀补全已经足够解决问题。
内容的提问来源于stack exchange,提问作者puneet sharma

