ES分页查询时出现超过一万页就爆出这个错误:Result window is too large, from + size must be less than or equal to: [10000] but…
该错误是由于es默认设置最大页数为一万的原因导致的,这样设置也是为了防止OOM。
第一种解决方式:
防止这个错误出现是设置 index.max_result_window的值。但是这种设置对CPU和内存的消耗会非常巨大,不太建议。
PUT { 索引名 }/_settings
{
"index":{
"max_result_window":{ 你想要的from+size最大值 }
}
}
第二种解决方式:
是使用es查询的深分页,使用的是scroll ,但是官方已经不再推荐采用Scroll API进行深度分页,下面说第三种
第三种解决方式:
这种方式适用查询分页超过10000页的数据查询,就是使用search_after 。
这种方式有一个缺点就是,因为点击查询下一页数的时候需要前一页的最后一条数据的唯一排序值。但是别怕,下面代码就已解决。
下面直接展示代码示例(很全,很简单):
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
SearchRequest request = new SearchRequest(EsIndex.ceshi); //这里就是请求你的es索引
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
Integer pageNum = Integer.valueOf(param.get("pageNum").toString());
//下面需要判断前端传过来的页数是否是第一页
//如果不是第一个,那我们需要先将当前页的前一页的数据查出来,并且拿到前一页数据的最后一条数据的唯一排序值。这里我们拿ceshi索引库中的ID作为唯一排序进行查询。
if(pageNum!=1){
SearchSourceBuilder sourceBuilder1 = new SearchSourceBuilder();
sourceBuilder1.query(boolQueryBuilder).sort("ID.keyword",SortOrder.DESC);
//此处减2就是获取当前页的前一页,减1就是当前页,因为from的值需要从0开始
sourceBuilder1.from((Integer.valueOf(param.get("pageNum").toString()) - 2) * Integer.valueOf(param.get("pageSize").toString())).size(Integer.valueOf(param.get("pageSize").toString()));
sourceBuilder1.trackTotalHits(true);
SearchRequest request1 = new SearchRequest(EsIndex.ceshi);
request1.source(sourceBuilder1);
//去查询
SearchResponse searchResponse1 = restHighLevelClient.search(request1, RequestOptions.DEFAULT);
//拿到前一页最后一个数据的ID值
SearchHit[] hits1 = searchResponse1.getHits().getHits();
Object[] sortValues1 = hits1[hits1.length - 1].getSortValues();
//再拿这个ID值进行searchAfter,查询下一页数据
sourceBuilder.query(boolQueryBuilder).sort("ID.keyword",SortOrder.DESC).searchAfter(sortValues1);
}
sourceBuilder.from(0).size(15);
sourceBuilder.trackTotalHits(true); //设置返回数据条数可以大于10000条
request.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
SearchHit[] hits = searchResponse.getHits().getHits();
2023-05-06更新
其实这种方式也是有问题,还是需要设置max_result_window,因为使用searchAfter就必须有上一页排序后的最后一条数据的唯一值,目前暂时没有想到解决方法,欢迎评论~