在ES中,每秒清空一次写缓冲,将这些数据写入文件,这个过程称为refresh,每次refresh会创建一个新的Lucene 段。但是分段数量太多会带来较大的麻烦,每个段都会消耗文件句柄、内存。每个搜索请求都需要轮流检查每个段,查询完再对结果进行合并;所以段越多,搜索也就越慢。因此需要通过一定的策略将这些较小的段合并为大的段,常用的方案是选择大小相似的分段进行合并。在合并过程中,标记为删除的数据不会写入新分段,当合并过程结束,旧的分段数据被删除,标记删除的数据才从磁盘删除。
默认情况下索引的refresh_interval为1秒,这意味着数据写1秒后就可以被搜索到,每次索引的refresh会产生一个新的Lucene段,这会导致频繁的segment merge行为,如果不需要这么高的搜索实时性,应该降低索引refresh周期
indexing buffer在为doc建立索引时使用,当缓冲满时会刷入磁盘,生成一个新的segment,这是除refresh_interval刷新索引外,另一个生成新segment的机会。每个shard有自己的indexingbuffer。
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
Elasticsearch 刚索引的文档并不是立即对搜索可见,它们会先在内存 buffer(缓存区)中,待 buffer 数据满后或主动刷新操作才会写入到文件缓存区中,便可以搜索。
手动让es中的数据每次更新后都从indexing buffer中刷新到磁盘中,从而让更新的数据立即可见,但是从前面的分析可见,会影响性能。
! 注意,经过验证,上文的代码在 8.17.8 版本不适用。
可以通过对应请求的 refresh 方法配置。
java
var builder = new UpdateRequest.Builder<Article, Map<?, ?>>();
builder.index(ElasticConstant.ARTICLE_INDEX);
builder.id(dto.getId()
.toString());
builder.doc(objectMapper.convertValue(dto, Map.class));
// 立刻刷新 ES
builder.refresh(Refresh.True);