Elastic Search Scroll API无限循环问题排查求助
解决Elasticsearch Scroll分批获取数据的无限循环问题
嘿,我一眼就看出你代码里的问题啦!这是个很容易疏忽的小错误,直接导致了无限循环。
问题根源
在你的while循环里,虽然你发起了新的滚动查询并得到了response,但最后更新resultsHits的时候,你仍然用的是第一次查询的searchResponse,而不是新返回的response。这样不管循环跑多少次,resultsHits永远是初始那批数据,长度始终大于0,循环根本停不下来!
看这段出错的代码片段:
while (resultsHits != null && resultsHits.length > 0) { SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId); searchScrollRequest.scroll(scroll); SearchResponse response = client.scroll(searchScrollRequest,RequestOptions.DEFAULT); scrollId = response.getScrollId(); // 这里错了!用了旧的searchResponse,而非新的response resultsHits = searchResponse.getHits().getHits(); logger.info("scrollId:{}",scrollId); logger.info("resultHits:{}",resultsHits.length); }
修正后的完整代码
只需要把resultsHits的赋值改成新的response的结果就行,另外我还补充了几个生产环境的最佳实践:
final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L)); // 把超时时间改合理,1毫秒太短了 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQuery) .sort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.DESC).size(10000); SearchRequest req = new SearchRequest("logs"); req.scroll(scroll); req.source(searchSourceBuilder); SearchResponse searchResponse = client.search(req, RequestOptions.DEFAULT); String scrollId = searchResponse.getScrollId(); SearchHit[] resultsHits = searchResponse.getHits().getHits(); logger.info("scrollId:{}",scrollId); while (resultsHits != null && resultsHits.length > 0) { SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId); searchScrollRequest.scroll(scroll); SearchResponse response = client.scroll(searchScrollRequest,RequestOptions.DEFAULT); scrollId = response.getScrollId(); // 改成使用新response的查询结果 resultsHits = response.getHits().getHits(); logger.info("scrollId:{}",scrollId); logger.info("resultHits:{}",resultsHits.length); // 在这里处理当前批次的数据,比如解析、存储等 // processBatchData(resultsHits); } // 重要:循环结束后必须清理Scroll上下文,避免占用ES内存资源 ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); clearScrollRequest.addScrollId(scrollId); client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
额外注意事项
- 你的原代码把Scroll超时时间设为1毫秒,这在实际场景中几乎一定会超时,建议改成1-5分钟,根据数据处理速度调整。
- 务必在循环结束后调用
ClearScrollRequest清理Scroll ID,否则Elasticsearch会一直保留这些滚动上下文,持续占用内存。
内容的提问来源于stack exchange,提问作者TeamZ
相关产品推荐
相关产品推荐

