提到elasticsearch分頁,可能首先想到的是類似mysql的那種處理方式,傳入分頁起始值以及每頁數據量,es確實提供了類似的處理策略,代碼如下:
@Test
public void searchFromSize() throws IOException{
SearchRequest searchRequest = new SearchRequest("sub_bank1120");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//每頁10個數據
searchSourceBuilder.size(10);
//起始位置從10開始
searchSourceBuilder.from(10);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] searchHits = searchResponse.getHits().getHits();
for(SearchHit s:searchHits){
println(s.getSourceAsString());
}
}
但是上述方式有一個嚴重的缺陷:from和size不能太大,兩者之和不能超過index.max_result_window,超過該值就會報
org.elasticsearch.client.ResponseException異常
Result window is too large, from + size must be less than or equal to: [10000] but was [11010]
爲什麼會使用index.max_result_window來限制搜索深度,因爲這需要耗費大量內存,比如from爲10000,es會按照一定的順序從每個分片讀取10010個數據,然後取出每個分片中排序前10的數據返回給協調節點,協調節點會將從所有分片節點返回的10條數據再次進行統一排序處理,以此來返回全局排序前10的數據,如果有類似的需要可以使用scroll以及search after來實現超大分頁問題,
scroll分頁示例代碼可以參考:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.8/java-rest-high-search-scroll.html
search after示例可以參考下面代碼:
/**
* search after
* @throws IOException
*/
@Test
public void searchAfter() throws IOException{
SearchRequest searchRequest = new SearchRequest("sub_bank1031");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("cityId", "511000"));
searchSourceBuilder.size(2);
//id動態映射爲text類型,排序不能使用分詞的字段,所以這裏選擇了id的keyword多字段屬性
searchSourceBuilder.sort(new FieldSortBuilder("id.keyword").order(SortOrder.ASC));
//
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] searchHits = searchResponse.getHits().getHits();
if(searchHits.length >0){
for(SearchHit s:searchHits){
println(s.getSourceAsString());
}
JSONObject json = JSON.parseObject(searchHits[searchHits.length-1].getSourceAsString());
String id = json.getString("id");
searchSourceBuilder.searchAfter(new Object[]{id});
searchRequest.source(searchSourceBuilder);
searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
for(SearchHit s:searchHits){
println(s.getSourceAsString());
}
}
}
下圖爲索引映射部分截圖:
PS:
search after與scroll相比簡單些,而且無狀態。