elasticsearch分頁獲取數據

提到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相比簡單些,而且無狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章