ElasticSearch底层原理
一句话总览(先给你大脑一个地图)
Elasticsearch = 分布式搜索引擎
本质 = Lucene(倒排索引) + 分片 + 副本 + 协调节点
核心思想只有一句:
用倒排索引,把“全文搜索”变成“词 → 文档ID”的快速查找
一、ES 的数据是怎么存的?(从磁盘说起)
1️⃣ Lucene 才是底层王者
Elasticsearch 不是自己做搜索的,它只是:
- 封装 Lucene
- 管理分布式(分片、副本)
- 提供 REST API
👉 真正干活的是 Lucene
2️⃣ Lucene 的核心:倒排索引(Inverted Index)
传统数据库(B+Tree)
docId -> 内容
倒排索引(搜索友好)
词 -> [docId1, docId2, docId3]
例子:
| 文档ID | 内容 |
|---|---|
| 1 | Java is powerful |
| 2 | Java and Elasticsearch |
| 3 | Elasticsearch is fast |
倒排索引:
java -> [1,2]
elasticsearch -> [2,3]
is -> [1,3]
👉 搜索速度本质上是:
查词典 + 合并 docId 集合
二、Index / Shard / Segment 的真实关系(重点)
这是面试必问,很多人都说不清。
1️⃣ Index ≠ 一个文件
Index
├── Shard 0
│ ├── Segment A
│ ├── Segment B
├── Shard 1
│ ├── Segment C
概念层级
| 层级 | 本质 |
|---|---|
| Index | 逻辑概念 |
| Shard | Lucene Index |
| Segment | 不可变的索引文件 |
2️⃣ Segment:为什么是不可变的?
这是 ES 性能的根基
好处
- 不需要加锁(读性能极强)
- 文件直接 mmap
- 支持 OS PageCache
代价
- 删除 ≠ 真删
- 更新 = 删旧 + 新增
👉 ES 没有“update”,只有“delete + insert”
3️⃣ Segment 合并(Merge)
随着写入:
- Segment 越来越多
- 查询会变慢
于是后台会:
- 合并小 segment
- 生成大 segment
- 旧 segment 被标记删除
⚠️ merge 很吃 IO 和 CPU
三、写入原理(Index 一条数据发生了什么)
这是高频面试题
1️⃣ 写入流程(完整)
请求
↓
协调节点
↓
路由到 Primary Shard
↓
写入内存 buffer
↓
写入 translog
↓
返回成功
2️⃣ 为什么要 translog?
因为:
- 内存 buffer 会丢
- segment 还没落盘
translog = ES 的 WAL
先写日志 → 再异步刷盘
崩溃恢复靠它。
3️⃣ refresh & flush 的区别(重点)
refresh(默认 1s)
- buffer → segment
- 数据可被搜索
- 不落盘
flush
- segment 落盘
- 清空 translog
👉 能搜到 ≠ 已持久化
四、查询原理(搜索是怎么跑的)
1️⃣ Query vs Fetch 两阶段
第一阶段:Query
- 每个 shard 执行查询
- 返回 docId + score(TopN)
第二阶段:Fetch
- 汇总 docId
- 回 shard 拉取 _source
- 返回给客户端
2️⃣ 为什么分页深了会慢?
from + size 的代价:
- 每个 shard 都要算
from + size - 丢弃前面大量数据
👉 深分页 = 灾难
正确方案
| 场景 | 方案 |
|---|---|
| 翻页 | search_after |
| 导出 | scroll |
| 前端 | 限制页数 |
五、相关度打分(BM25)
ES 默认算法:BM25
核心因素:
- 词频 TF
- 逆文档频率 IDF
- 字段长度归一化
本质公式(理解即可):
score ≈ TF * IDF * norm
👉 为什么 keyword 不参与评分?
- 因为它不分词
- 本质是精确匹配
六、分布式核心:Shard & Replica
1️⃣ 为什么要分片?
- 单机磁盘有限
- 单机 CPU 有限
Shard 本质:
一个 shard = 一个 Lucene Index
2️⃣ Primary & Replica
- Primary:写
- Replica:读 + 容灾
写流程:
写 Primary
↓
同步 Replica
↓
返回成功
3️⃣ 为什么副本也能查?
因为:
- segment 是不可变的
- replica 结构完全一致
👉 ES 天生支持读扩展
七、为什么 ES 不适合事务?
因为它的设计目标是:
| 能力 | 是否支持 |
|---|---|
| 强一致 | ❌ |
| 事务 | ❌ |
| 高并发搜索 | ✅ |
| 近实时 | ✅ |
ES 是 Near Real-Time(NRT)
八、面试官最爱追问(你必须会)
我直接给你标准回答方向:
Q1:ES 为什么比 MySQL 快?
倒排索引 + 顺序 IO + mmap + 不可变 segment
Q2:delete/update 为什么慢?
标记删除 + segment merge
Q3:为什么不建议 shard 太多?
shard = Lucene Index,资源消耗大
Q4:ES 会丢数据吗?
refresh 前可丢,translog 保证 crash 恢复
九、一句工程级总结(记住)
ES 的本质是:
用 Lucene 的倒排索引做全文搜索,
用 shard + replica 做分布式,
用 refresh 实现近实时。
浙公网安备 33010602011771号