ES / Lucene
数据流转流程图
📝
数据写入流程
1
原始文档输入
ES层
客户端发送 JSON 文档到 ES REST API (9200端口)
输入数据结构
{ "title": "Elasticsearch实战", "author": "张三", "content": "分布式搜索引擎详解", "views": 12345 }
↓
2
路由计算
ES层
根据
_uid
计算目标分片
路由公式
shard_num = hash(_uid) % primary_shards
↓
3
Memory Buffer
内存
文档写入内存缓冲区,同时写入 Translog (保证持久性)
内存状态
[ Doc 1: {title: "A", content: "foo"}, Doc 2: {title: "B", content: "bar"}, Doc 3: {title: "C", content: "baz"} ]
↓ refresh (1秒)
4
Segment (内存)
内存
Lucene
缓冲区数据生成新的 Segment,建立倒排索引
索引结构
倒排索引已创建,可被搜索
↓ flush (或达到阈值)
5
Segment Files
磁盘
Lucene
Segment 刷到磁盘,Translog 清理
磁盘文件结构
index/
_0.tim
(倒排表 - Term Dictionary)
_0.tip
(词典索引)
_0.doc
(正排表 - Doc IDs)
_0.fnm
(字段定义)
_0.nvd
(评分因子)
translog/
translog.ckp
↓ 后台合并
6
Segment Merge
磁盘
Lucene
后台线程合并小 Segment 为大 Segment,减少文件数量
📍 写入流程总结
Document → 路由计算 → Memory Buffer → Segment(内存) → Segment(磁盘) → Merge
Translog 贯穿全程,保证故障可恢复
Refresh 默认 1 秒,实现近实时搜索
🔍
数据查询流程
1
Query 输入
ES层
客户端发送搜索请求到 ES REST API
查询示例
GET /my_index/_search { "query": { "match": { "content": "搜索" } } }
↓
2
Query Parsing & Routing
ES层
解析查询条件,计算目标分片 (可能分散在多个节点)
↓
3
IndexSearcher
内存
Lucene
创建搜索器,并行遍历所有 Segment
↓ Query Phase
4
Query Phase (查询阶段)
Lucene
遍历倒排索引,找到匹配文档,计算评分
倒排表查询过程
1. 在 .tim 中定位 Term "搜索" 2. 读取倒排列表 (Postings) 3. 计算 BM25/TF-IDF 评分 4. 取每个 Segment 的 Top N 5. 归并排序取全局 Top 10
↓ Fetch Phase
5
Fetch Phase (获取阶段)
Lucene
根据 DocId 从 .doc 文件加载原始文档
正排表读取
DocId 3 → 从 .doc 加载原始 JSON DocId 7 → 从 .doc 加载原始 JSON DocId 15 → 从 .doc 加载原始 JSON
↓
6
组装结果返回
ES层
聚合各分片结果,返回给客户端
📍 查询流程总结
Query → 解析/路由 → IndexSearcher → Query Phase → Fetch Phase → 返回
Query Phase: 遍历倒排索引,找到匹配文档
Fetch Phase: 根据 DocId 拉取原始文档
写入用正排建倒排,查询从倒排找正排
⚖️
写入 vs 查询 对比
📝 写入
方向: Document → Index
数据结构: 正排表 → 倒排表
内存: Buffer → Segment
磁盘: Segment Files
Translog: 写入 (保证持久)
关键组件: IndexWriter
🔍 查询
方向: Query → Documents
数据结构: 倒排表 → 正排表
内存: IndexSearcher
磁盘: Segment Files (.tim/.doc)
Translog: 不涉及
关键组件: IndexSearcher
ES层
内存
磁盘
Lucene