elasticsearch分页查询
scroll 查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
游标查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 cursor 。
游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 '视图' 一样。
深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段 _doc 来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。
启用游标查询可以通过在查询的时候设置参数 scroll 的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。
public void scrollAndProcess(String queryString, CallBack<TeamES> callBack, boolean process) {
try {
SearchResult scrollRsp = scanService.scan(EsConstant.ESV5_TEAM_INDEX, SCROLL, null, 500, queryString);
long totalHits = scrollRsp.getHits().getTotalHits();
boolean toScan = totalHits > 0 || scrollRsp.getLeftNumber() > 0;
while (toScan) {
List<TeamESV5> list = scrollRsp.getHits().getHits().stream()
.map(hit -> JSON.parseObject(JSON.toJSONString(hit.getSource()), TeamESV5.class))
.collect(Collectors.toList());
List<TeamES> teamESList = orikaBeanUtil.convertList(list, TeamES.class);
if (process) {
teamESList.forEach(callBack::doBiz);
} else {
logger.info("kdtIdList:", teamESList.stream().map(TeamES::getKdtId).collect(Collectors.toList()));
}
scrollRsp = scanService.scan(EsConstant.ESV5_TEAM_INDEX, SCROLL, scrollRsp.getScrollId(), 500, null);
toScan = scrollRsp.getLeftNumber() > 0;
}
if (scrollRsp.getCode() != 0) {
logger.warn("scroll end:{}", scrollRsp.getMessage());
}
} catch (Exception e) {
logger.error("scrollAndProcess failed,{}", e.getMessage());
}
}
浙公网安备 33010602011771号