一、引言:为什么需要 Refresh?
在 TongSearch中,写入成功 ≠ 立即可查询。
这背后最关键的一个机制就是:
Refresh(刷新)机制
它决定了写入的数据何时可被搜索到,而不是什么时候写入成功。
二、数据写入与可见性的区别
写入流程回顾:
Index 请求
↓
写入内存 buffer(RAM) + Translog
↓
Lucene 的 segment 并未立即更新
↓
Lucene 查询无法看到这些内存数据
↓
直到 Refresh 发生
简而言之:
写入内存 ≠ Lucene 可搜索
刷新(refresh) ≈ 把内存数据提交为 segment,让 Lucene 知道它存在
三、什么是 Refresh?
Refresh 是 TongSearch/Lucene 中的一个机制,用于:
将内存中的文档 buffer(SegmentWriter buffer)刷新为一个新的 segment,使其变得可搜索(searchable)。
其本质是调用:
IndexWriter.getReader(); // 开启一个新的 IndexReader
而生成一个新的 Searcher,以支持后续查询请求。
四、Refresh 的触发机制
TongSearch中 Refresh 有三种触发方式:
触发方式
描述
自动刷新
默认每隔 1 秒执行一次,由 IndexSettings.INDEX_REFRESH_INTERVAL_SETTING 控制
手动刷新
用户显式调用 _refresh API
实时刷新(Near Real-Time)
特定操作(如 GET)需要时,可能强制打开 reader 实现“伪实时”读取
示例:修改 refresh interval
PUT my-index/_settings
{
"index": {
"refresh_interval": "30s"
}
}
五、刷新流程详解
1)文档写入后进入内存 buffer
所有写入数据暂存于 Lucene 的 RAM buffer 中
写入也同步记录到 Translog,以确保崩溃后能恢复
2)调用 refresh() 方法
刷新流程本质:
IndexWriter.getReader() // 开启新的 reader
Lucene 将会:
创建一个新的 segment(内存 segment)
将这些 segment 暴露为一个新的 IndexReader
将新的 reader 更新到 IndexShard.searcher 中,供搜索使用
这一步是轻量级的,不涉及磁盘写入。
3)旧 Searcher 被关闭(延迟释放)
TongSearch使用 SearcherManager 管理 reader
老的 reader 不会立刻释放(Zero Downtime Search)
支持多个并发查询仍能读取老版本数据(直到 GC)
六、Refresh 与 Flush 的区别
操作
是否写磁盘
是否可查询
是否清理 translog
Refresh
❌ 否
✅ 是
❌ 否
Flush
✅ 是
✅ 是
✅ 是(创建 commit point)
Refresh ≠ 持久化,只是数据“可搜索”而非“可恢复”!
要确保写入能 survive 重启,还需等 translog 落盘(或 flush)。
七、Refresh 与性能的关系
频繁刷新 = 更多 segment = 查询性能下降
所以在一些场景下,应该:
增大 refresh interval,降低写入系统压力
批量导入时设置为 -1(禁止自动刷新),导入完成后手动 _refresh
PUT /my-index/_settings
{
"index": {
"refresh_interval": "-1"
}
}
八、Refresh 与实时搜索
TongSearch是 Near Real-Time 搜索系统,默认 1 秒可见。
你可以控制“是否等待 refresh 后可见”:
示例:立即可见写入
POST /my-index/_doc/1?refresh=wait_for
{
"title": "立即可见"
}
九、总结
Refresh 本质
将内存 buffer 刷新为 Lucene 可查询的 segment
默认触发
每隔 1 秒一次,可配置或关闭
是否写磁盘
否,仅在内存中创建 reader
是否可搜索
是,刷新后 Searcher 才能看到数据
适用场景
提高查询可见性,但频繁刷新会增加 segment 数量