事情本身不复杂,线索都在日志里。商品搜索用 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 子字段做双路查询,比改分词词典更可控。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189