NiceOffer

八股文解析

Elasticsearch 为什么搜索快?倒排索引原理

Elasticsearch搜索八股文

一句话结论

ES 搜索快靠的是倒排索引(Inverted Index),它把“文档→词”的扫描问题变成“词→文档”的 O(1) 查找。

面试标准答法

1. 核心机制:倒排索引(Inverted Index)

正向索引(Forward Index) 是传统关系型数据库的存储方式:每行记录存一个文档 ID,查询时全表扫描匹配字段内容。数据量到百万级,全表扫描必然超时。

倒排索引 反向构建:先对每个文档做分词(Tokenizer + Analyzer),得到词条(Term)列表,然后建立 Term → 包含该 Term 的文档 ID 列表(Posting List) 的映射。

文档1: "Elasticsearch is fast"
文档2: "Elasticsearch uses inverted index"

倒排索引(简化):
"elasticsearch" → [doc1, doc2]
"fast"          → [doc1]
"uses"          → [doc2]
"inverted"      → [doc2]
"index"         → [doc2]

查询 "elasticsearch" 时,直接从索引中取出 [doc1, doc2],无需扫描全部文档。

2. 加速细节:不只是倒排索引

倒排索引只是基础,ES 还叠加了以下机制,层层加速:

2.1 Term Dictionary + Term Index(FST)

  • Term Dictionary:所有不重复词条的排序列表,用于定位某个 Term 在 Posting List 中的位置。
  • Term Index:对 Term Dictionary 的前缀构建 FST(Finite State Transducer,有限状态转换器),常驻内存,将 Term 查找从二分查找 O(log N) 降到近似 O(1)。

FST 是 ES 搜索快的关键点之一:它把几十 GB 的词典压缩成几百 MB 的内存结构,同时保留前缀共享,支持模糊匹配和前缀查询。

2.2 Posting List 的压缩与跳表

  • Frame of Reference(FOR):对文档 ID 做增量编码(Delta Encoding),再用 Bit Packing 压缩,减少存储和 I/O。
  • Roaring Bitmap:当 Posting List 足够密集时,ES 自动切换为位图存储,利用 CPU 位运算加速交集/并集。
  • 跳表(Skip List):Posting List 内部维护跳表指针,多 Term 求交集(如 must 查询)时,跳过不匹配的文档,减少比较次数。

2.3 分段存储(Segment)与合并

  • 每个 Segment 是一个独立的倒排索引,写入时先进内存 buffer,refresh 后生成 Segment。
  • 查询时并行搜索所有 Segment,结果合并返回。
  • 后台 Merge 线程定期合并小 Segment 为大 Segment,删除旧版本,保证查询效率不随 Segment 数量退化。

2.4 列式存储:Doc Values

  • 排序、聚合、脚本计算需要读取字段原始值,ES 用 Doc Values(列式存储)替代倒排索引,避免对倒排索引做反查。
  • 列式存储按列连续存放,压缩率高,读取时只需加载涉及的列,跳过无关数据。

3. 对比表格

维度正向索引(MySQL InnoDB)倒排索引(Elasticsearch)
数据结构B+ TreeTerm → Posting List + FST
查询方式索引扫描 + 回表Term 查找 + 位图/跳表合并
适合场景等值查询、范围查询、事务全文检索、模糊匹配、聚合分析
写入效率高(原地更新)中(写缓冲 + 分段合并)
存储开销高(索引+字段副本)
典型延迟毫秒级(单行) / 秒级(全表)毫秒级(即使全量)

常见追问

追问要点
为什么 MySQL 不用倒排索引?MySQL 主场景是等值/范围查询,B+ Tree 有序性天然支持;全文检索用倒排索引但实现弱(ngram 分词差)。ES 牺牲写入和事务,换取查询灵活性。
ES 写入慢是为什么?写入要经过分词、构建倒排索引、写 translog、refresh 生成 Segment、定期 merge。每一步都有开销,但都是为查询快做铺垫。
为什么聚合慢?聚合走 Doc Values 列式存储,虽然比行式快,但需要遍历所有匹配文档的列值,计算量随数据量线性增长。
倒排索引能存数值吗?可以,但数值范围查询效率不如 B+ Tree。ES 对数值类型默认同时建倒排索引和 Doc Values,前者用于过滤,后者用于排序聚合。

面试回答模板(30 秒版)

延伸准备

  1. FST 原理:能画图解释 FST 如何共享前缀、如何用有限状态机表示词典,以及为什么比 HashMap 更省内存(前缀压缩 + 有序性支持范围查询)。
  2. Roaring Bitmap vs BitSet:说明 Roaring Bitmap 如何分桶存储(高 16 位分桶,低 16 位用数组或位图),以及为什么在稀疏/密集场景下都有优势。
  3. ES 与 Lucene 的关系:ES 底层是 Lucene 库,倒排索引、Segment、Doc Values 都是 Lucene 的能力,ES 只负责分布式协调、REST API 和集群管理。能讲清这层关系,说明你对 ES 架构有整体认知。

想系统备战大厂大模型/Agent 开发?NiceOffer 提供 SDE+LLM 双轨 1v1 陪跑,合同保底 40w 年薪,文末扫码咨询。