倒排索引与分词
用途:解释“为什么这个关键词搜不到”、设计文本检索方案
从正排到倒排
「从正排到倒排」小节链接| 结构 | 形态 | 适合 |
|---|---|---|
| 正排(doc → terms) | 文档到词项列表 | 按 ID 取文档 |
| 倒排(term → docs) | 词项到文档列表(含位置、频次) | 关键词检索、布尔组合、相关性打分 |
倒排表关键组成:
- 词典(Term Dictionary):词项有序,支持前缀/范围查找;常驻内存的 FST 结构做前缀索引。
- 倒排列表(Postings):文档 ID(delta 编码压缩)、词频、位置(用于短语查询)、偏移(用于高亮)。
- Skip List:加速多条件求交。
- Skip Data / Positions:位置信息让
match_phrase、邻近查询与高亮成为可能,代价是索引膨胀。
分词(Analysis)
「分词(Analysis)」小节链接字符过滤(去 HTML) → 分词器 Tokenizer(切词) → 词元过滤 Token Filter(小写、停用词、同义词、词干化)| 语言 | 常用分词器 |
|---|---|
| 英文 | standard、english(词干化)、keyword(不分词) |
| 中文 | ik_max_word / ik_smart、pinyin、分词插件(如 IK、HanLP 类)、或 ngram 兜底 |
| 精确匹配字段 | keyword 类型(不分词,用于 ID、状态、枚举、聚合排序) |
索引时分词与查询时分词必须一致(或显式指定 search_analyzer),否则会出现“存进去搜不出来”。典型场景:同义词只在查询侧展开,避免索引膨胀。
为什么需要 text + keyword 双字段
「为什么需要 text + keyword 双字段」小节链接text 分词后可全文检索但不可排序/聚合(成本高且语义不对);keyword 精确但无法部分匹配。用 fields 多字段映射同时支持:
{ "title": { "type": "text", "fields": { "kw": { "type": "keyword" } } } }打分基础(BM25)
「打分基础(BM25)」小节链接现代默认是 BM25,三要素:
- TF 饱和:词频贡献有上限(
k1),避免长文档堆词得高分。 - IDF:越稀有的词权重越高。
- 字段长度归一(
b):短字段命中得分更高。
工程含义:搜索结果“不符合直觉”往往不是 bug,而是相关性打分与业务排序需求不一致 → 用 function_score、字段权重、业务分(热度、时间衰减)重排,或改精确过滤 + 应用层排序。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
用 LIKE '%x%' 思路期待 ES 行为 |
ES 是词项匹配,不是子串匹配;子串需求用 ngram/wildcard 类型 |
所有字段都设 text |
无法聚合排序且索引膨胀 |
| 索引与查询分析器不一致 | 显式配置 analyzer / search_analyzer |
| 停用词删太多导致短语查询失真 | 结合业务语料评估 |
| 同义词写进索引分析器 | 索引后改同义词需重建索引,放查询侧更灵活 |
中文用 standard 分词 |
会按单字切,召回噪声大 |
延伸阅读
「延伸阅读」小节链接- Elasticsearch 官方文档:Inverted index、Analyzers、BM25 相关性
- 《Relevant Search》(Mansfield & Barsky,相关性调优)
- IK 等中文分词插件文档与词典维护实践