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