跳转到内容

倒排索引与分词

用途:解释“为什么这个关键词搜不到”、设计文本检索方案

结构 形态 适合
正排(doc → terms) 文档到词项列表 按 ID 取文档
倒排(term → docs) 词项到文档列表(含位置、频次) 关键词检索、布尔组合、相关性打分

倒排表关键组成:

  • 词典(Term Dictionary):词项有序,支持前缀/范围查找;常驻内存的 FST 结构做前缀索引。
  • 倒排列表(Postings):文档 ID(delta 编码压缩)、词频、位置(用于短语查询)、偏移(用于高亮)。
  • Skip List:加速多条件求交。
  • Skip Data / Positions:位置信息让 match_phrase、邻近查询与高亮成为可能,代价是索引膨胀。
字符过滤(去 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,三要素:

  • 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 等中文分词插件文档与词典维护实践