中文分词与 BM25
BM25 是词项匹配模型:文档与查询被切成词项后按词频、文档频率与文档长度打分。中文没有天然空格,分词粒度直接决定召回——切得太碎则长词片段匹配不上,切得太粗则短语命中被漏掉。Elasticsearch 常用的 IK 插件提供两套分析器:ik_max_word 在索引时做细粒度切分以提高召回,ik_smart 在查询时做粗粒度切分以减少噪声,这是常见的组合。产品型号、品牌与缩写必须加入自定义词典,否则会被切坏,检索永远命不中。
基本信息
| 框架 | Elasticsearch / OpenSearch + analysis-ik 插件 |
|---|---|
| 分析器 | ik_max_word(细粒度)、ik_smart(粗粒度) |
| 常用组合 | 索引用 ik_max_word,查询用 ik_smart |
| 打分参数 | BM25 默认 k1=1.2、b=0.75 |
| 词典 | 自定义词典扩展专名;更新后需重建索引 |
典型使用场景
- 中文知识库的关键词一路:与向量检索组成混合检索,兜住专名与型号
- 技术文档检索:产品名、版本号、命令名必须原样命中
- 多语言语料:按语种配置不同分析器,避免用英文分析器切中文
- 召回骤降排查:先看查询词被切成什么,再判断是词典问题还是分析器问题
- 接入新词表:上线前在新词上做正反向用例验证,确认索引与查询两侧行为一致
字段映射与分析器
字段映射与分析器
PUT kb_chunks
{
"settings": { "analysis": { "analyzer": { "ik_smart_q": { "type": "custom",
"tokenizer": "ik_smart" } } } },
"mappings": { "properties": {
"content": { "type": "text",
"analyzer": "ik_max_word", // 索引:细粒度提高召回
"search_analyzer": "ik_smart" } } } // 查询:粗粒度减少噪声
}验证分词结果
验证分词结果
GET _analyze
{ "analyzer": "ik_max_word", "text": "ruijie RG-S2910 交换机" }
# 输出 tokens 列表:确认型号未被切碎
# 若被切碎,把型号加入自定义词典后重建索引分析器选择的影响
| 配置 | 召回 | 精确度 | 适用 |
|---|---|---|---|
| 索引/查询都用 ik_max_word | 高 | 偏低 | 短查询、术语不规范的语料 |
| 索引 max + 查询 smart | 较高 | 较高 | 通用中文检索,推荐起点 |
| 索引/查询都用 ik_smart | 偏低 | 高 | 查询词本身就是完整术语 |
| 未装插件用标准分析器 | 极低 | 不可用 | 仅英文或数字场景 |
自定义词典更新后,新词只对新写入的文档生效:倒排索引里已经切碎的文档必须重建(或 reindex)才能被命中,这一点常被忽略。