事情本身不复杂,线索都在日志里。商品搜索用 Elasticsearch 8.13 的 ik_max_word 分析器建索引,用户搜「X1 碳刷」时召回为零,用 match_phrase 才能命中,原因是型号被切成 x 与 1 两个 token。
第一反应是「没有为型号字段单独配置 keyword 子字段」,验证下来不成立。
这类报错背后常见的原因有几处,逐个排除就行。ik 分词把手写字母数字混排的词拆开。少数情况下是索引与查询用了不同的分析器。
不容易想到的是,同义词表里缺少型号的等价写法。
第一件事是看分词结果确认切法
curl -s -XPOST "http://localhost:9200/goods/_analyze" -H "Content-Type: application/json" -d '{"analyzer":"ik_max_word","text":"X1 碳刷"}' | jq '.tokens[].token'
为型号字段加 keyword 子字段走精确匹配
curl -s -XPUT "http://localhost:9200/goods/_mapping" -H "Content-Type: application/json" -d '{"properties":{"model":{"type":"text","analyzer":"ik_max_word","fields":{"raw":{"type":"keyword"}}}}}'
接着查询时用 bool 组合精确与分词两路
curl -s -XPOST "http://localhost:9200/goods/_search" -H "Content-Type: application/json" -d '{"query":{"bool":{"should":[{"term":{"model.raw":"X1"}},{"match":{"title":"碳刷"}}]}}}'
末了用 20 条真实 query 回归召回率
python es_eval.py --queries queries.txt --index goods --min-recall 0.9
改完先别撤,确认这几项。型号查询走精确字段后「X1 碳刷」能召回 37 条,20 条回归 query 的召回率升到 95%,泛词查询结果没有变差。
容易忽略的是,中文分析器天生不适合处理字母数字混排的型号,给字段加 keyword 子字段做双路查询,比改分词词典更可控。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
