Skip to content

ES 倒排索引深度解析

面试官:ES 为什么搜索这么快?

:核心是倒排索引。ES 在写入文档时会对文本字段进行分词,建立「词项 → 文档列表」的倒排索引,查询时直接定位词项对应的文档,不需要全表扫描。

面试官:倒排索引和数据库的 B+树索引有什么根本区别?


Q1:倒排索引的数据结构是什么?必考

Section titled “Q1:倒排索引的数据结构是什么?”

正排索引(Forward Index):文档 ID → 文档内容(数据库 B+树就是正排)

倒排索引(Inverted Index):词项 → 包含该词项的文档列表

假设有 3 个文档:
Doc1: "Java 是世界上最好的语言"
Doc2: "Python 是 AI 领域最热门的语言"
Doc3: "Java 和 Python 都是优秀的语言"
分词后的倒排索引:
词项 | Posting List(文档 ID 列表)
---------|----------------------------------
Java | [Doc1(TF:1), Doc3(TF:1)]
Python | [Doc2(TF:1), Doc3(TF:1)]
语言 | [Doc1(TF:1), Doc2(TF:1), Doc3(TF:1)]
AI | [Doc2(TF:1)]
优秀 | [Doc3(TF:1)]

Posting List 中存储的信息

  • DocID:文档 ID
  • TF(Term Frequency):词项在文档中出现的频率(用于相关性评分)
  • 位置信息(Position):词项在文档中的位置(用于短语查询)
  • 偏移量(Offset):字符位置(用于高亮显示)

Q2:倒排索引的词项字典是怎么存储的?FST 是什么?高频

Section titled “Q2:倒排索引的词项字典是怎么存储的?FST 是什么?”

词项字典(Term Dictionary)存储所有不重复的词项,需要支持:

  1. 快速精确查找(term 查询)
  2. 前缀匹配(prefix 查询)
  3. 范围查询(range 查询)

ES 使用 FST(Finite State Transducer,有限状态转换器) 压缩存储词项字典:

假设词项:java, javascript, python
普通存储:全部存入磁盘,占用大量内存
FST 存储:共享公共前缀 "java",树形结构
(root)
/ \
java python
|
script
优势:
- 极高的压缩率(类似 Trie 树但更紧凑)
- 整个词项字典可以加载到内存(即使几十GB的索引)
- O(len) 的查找时间复杂度

与 MySQL B+树的根本区别

维度MySQL B+树ES 倒排索引
适合查询等值、范围查询全文搜索、模糊查询
查询方向属性 → 文档词项 → 文档集合
空间优化无压缩FST 压缩 + Posting 压缩
更新代价B+树节点分裂Segment 不可变,写新 Segment

Q3:Posting List 是如何压缩存储的?

Section titled “Q3:Posting List 是如何压缩存储的?”

ES 的 Posting List 存储大量文档 ID,ES 使用多种压缩技术:

1. Delta 编码(差分编码)

原始 DocID:[1, 3, 7, 15, 16, 19]
差分值: [1, 2, 4, 8, 1, 3]
存储差分值,减少数字大小,更利于压缩

2. Frame Of Reference(FOR):将差分值按固定块(128个)分组,每块只用最少的 bit 数存储。

3. Roaring Bitmap:当文档量很大时,使用 Roaring Bitmap 存储文档 ID 集合,支持高效的集合运算(AND/OR/NOT),用于多条件查询的快速合并。


Q4:ES 的分词器是怎么工作的?常用的分词器有哪些?必考

Section titled “Q4:ES 的分词器是怎么工作的?常用的分词器有哪些?”

分词器(Analyzer) 由三部分组成:

Character Filter(字符过滤器)
└── 处理原始文本,如去除 HTML 标签、替换字符
Tokenizer(分词器核心)
└── 将文本切分为词项(Token)
Token Filter(词项过滤器)
└── 对词项进行处理:转小写、去停用词、词干提取等

常用分词器

分词器适用语言特点
standard英文(默认)按空格和标点分词,转小写
whitespace英文仅按空格分词,不做其他处理
ik_max_word中文IK 中文分词,最细粒度切分
ik_smart中文IK 中文分词,最粗粒度切分(推荐用于搜索)
jieba中文结巴分词,支持自定义词典

中文搜索最佳实践

{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "ik_max_word",
"user_dict": "my_dict.txt"
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}

分析器不一致的坑:索引时用 ik_max_word(细粒度),搜索时用 ik_smart(粗粒度),可以提高召回率。


Q5:text 类型和 keyword 类型的区别?

Section titled “Q5:text 类型和 keyword 类型的区别?”
类型是否分词适用场景支持聚合
text✅ 分词后建倒排索引全文搜索、模糊匹配❌(需要 fielddata,内存开销大)
keyword❌ 整体作为一个词项精确匹配、排序、聚合

典型配置(同时支持全文搜索和聚合)

"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}

查询时用 title(全文搜索),聚合时用 title.keyword(精确值)。