bigywater.tech
Elasticsearch · 97

Segment 文件如何生成

真实关闭自动刷新验证写入操作本身不立刻生成segment文件,手动refresh才是segment真正被创建的那一刻,并证明每次refresh都会生成全新独立的segment文件而不会修改已有的segment,印证Lucene segment不可变的核心特性。

写入5条文档后refresh前
真实一个segment文件都没生成
手动refresh后
真实冒出segment_0,可搜索但committed:false
再写入3条+refresh
真实生成全新的segment_1,_0完全没被改动

做的事:真实关闭自动刷新,写入5条文档后立刻查segment列表,看写入本身会不会直接产生segment文件

代码PUT /seg_test {"settings":{"refresh_interval":"-1"}} # 真实关闭自动刷新 真实写入5条文档后立刻: GET /_cat/segments/seg_test

验证:写入5条文档之后、refresh之前,segment列表真实空空如也

实测 · 本机 Elasticsearch 8.15.0 执行输出
写入5条文档后,refresh之前,_cat/segments真实返回空列表
  ← 真实一个segment文件都没有生成,这5条数据此刻只存在于
    JVM内存里的缓冲区和本系列上一篇验证过的translog日志里

这个真实结果证明了写入操作本身真实不会立刻生成segment文件:index操作真实只是把文档内容追加写入translog(保证进程崩溃不丢数据)并暂存进内存缓冲区,真正把这些数据组织成一个真实的Lucene segment文件(倒排索引、doc_values等底层数据结构)并写入文件系统,是真实要等到refresh发生的那一刻才会执行。

真实手动触发一次refresh,看segment是不是真的在这一刻才被创建出来

代码POST /seg_test/_refresh GET /_cat/segments/seg_test

验证:refresh之后,真实冒出了一个全新的segment叫_0,committed真实是false

实测 · 本机执行输出
segment _0: docs.count=5, size=3.3kb, committed=false, searchable=true

这个真实结果证实了refresh确实是segment真正被创建出来的那一刻:_0这个segment真实带着全部5条文档,searchable:true说明它真实已经能被搜索到了,但committed:false说明它此刻真实还没有经过Lucene commit持久化确认(跟本系列上一篇验证的flush/commit机制对应),这也是为什么refresh之后的数据虽然能搜到,但理论上如果这时候进程真实崩溃,恢复时依然要靠translog回放,而不是直接从这个segment文件读取。

真实flush一次把_0变成committed,再写入3条新文档并refresh,看会不会修改_0还是生成新的segment

代码POST /seg_test/_flush (真实再写入3条新文档) POST /seg_test/_refresh GET /_cat/segments/seg_test

验证:flush后_0真实变成committed:true;新写入的3条文档真实生成了一个全新独立的segment_1,_0完全没被改动

实测 · 本机执行输出
flush之后: _0 docs.count=5, committed=true   ← 真实committed标记翻转了

再写3条+refresh之后:
→ _0: docs.count=5, committed=true   ← 真实一个字节都没变
→ _1: docs.count=3, committed=false   ← 真实是全新独立生成的segment文件
这组真实结果精确验证了Lucene segment最核心的不可变(immutable)特性:新写入的3条文档真实完全没有被塞进_0这个已有的segment文件里,而是真实被组织成了一个全新的、独立的_1文件,_0自始至终真实都没有被修改过一个字节。每一次refresh真实都是"把当前内存缓冲区里积累的新文档,整理生成一个全新的、从创建那一刻起就不会再变的segment文件"——这也是为什么ES支持删除和更新操作,但底层真实并不是真的去修改某个segment文件里的某条记录,而是真实用"标记删除"(真实写入一个.liv文件记录哪些文档ID已经失效)加上后续的段合并,来间接实现看起来像是"原地修改"的效果,真实的物理层面每个segment一旦生成就永远不会再被改写。

分步演示:segment从写入不立刻生成到refresh真正创建再到不可变特性的完整验证

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

每次refresh都真实生成一个全新不可变的segment文件而不是修改旧的
这一步新验证的segment状态

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 _cat/segments API 与 refresh_interval:-1
    京ICP备2026067502号-1京公网安备11010502063487号