真实灌5万条数据对比completion suggester和prefix查询的耗时差异与总命中数计算开销,并验证completion suggester内置的fuzzy参数相对prefix查询在拼写容错能力上的真实优势。
代码PUT /comp_test {"mappings":{"properties":{ "suggest": {"type":"completion"}, "title": {"type":"text"} }}} 真实灌50000条数据,每条是7个水果名之一加随机数字(如"apple247") POST /comp_test/_search {"suggest":{"s1":{"prefix":"app","completion":{"field":"suggest","size":5}}}} POST /comp_test/_search {"size":5,"query":{"prefix":{"title":"app"}}}
completion suggester 搜"app": took=7ms, 0ms, 0ms → 真实返回5个候选: apple247/apple565/apple841/apple89/apple932 prefix查询 搜"app": took=5ms, 2ms, 2ms → 真实返回同样的5条,但额外计算出 hits.total.value=7196(全部匹配的文档数)
这组真实耗时对比揭示了两者底层架构的真实区别:completion这个字段类型在索引阶段真实就把所有候选词构建成了一棵驻留在内存里的FST(有限状态转换机)结构,查询时真实只需要沿着这棵树按前缀走到对应节点,直接截取前N个结果返回,完全不需要关心"总共有多少条匹配"这件事;而prefix查询真实走的是标准的查询打分路径,哪怕只要前5条结果,底层真实也要扫描并统计出全部7196条匹配文档的数量(这是hits.total.value精确计数的代价),这个真实的计数开销是completion suggester从设计上就主动省掉的。
代码用户真实打错了字,输入"aple"(少了一个p,正确应该是apple) POST /comp_test/_search {"suggest":{"s1":{"prefix":"aple","completion":{"field":"suggest","size":5}}}} POST /comp_test/_search {"suggest":{"s1":{"prefix":"aple","completion":{"field":"suggest","size":5,"fuzzy":{"fuzziness":1}}}}}
不开fuzzy,搜"aple": options = [] ← 真实一个候选都没有 开fuzziness=1,搜"aple": options = ['apple247','apple565','apple841','apple89','apple932'] ← 真实全部5个apple开头的候选都被正确召回了
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
completion 字段类型与 suggest API