您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何解決ES深度分頁問題”,在日常操作中,相信很多人在如何解決ES深度分頁問題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何解決ES深度分頁問題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
ES深度分頁問題:
ES 默認采用的分頁方式是 from+ size 的形式,類似于MySQL的分頁offset+limit。當請求數據量比較大時,Elasticsearch會對分頁做出限制,因為此時性能消耗會很大。例如查詢1000條數據,假設我們有5個分片,那么每個shard都需要返回1000條數據給 coordinating node,而 coordinating node 需要接收 5*1000 條數據,進行排序后返回1000條數據給客戶端。即使每條數據只有 _doc _id 和 _score,這數據量也很大了,如果請請求量很大的情況下,很容易造成ES的OOM。ES中有個設置
index.max_result_window
,默認是10000條數據,如果分頁的數據超過第1萬條,就拒絕返回結果了。如果集群配置比較好,查詢請求量不是特別大,可以適當的放大這個參數。
解決方案:
1:使用scroll遍歷
scroll 分為初始化和遍歷兩步,初始化時將所有符合搜索條件的搜索結果緩存起來,可以想象成快照,在遍歷時,從這個快照里取數據,也就是說,在初始化后對索引插入、刪除、更新數據都不會影響遍歷結果。因此,scroll 并不適合用來做實時搜索,而更適用于后臺批處理任務等
API說明:
1)初始化
POST /book/_search?scroll=1m&size=2 { "query": { "match_all": {}} }
遍歷
GET /_search/scroll { "scroll": "1m", "scroll_id" : "步驟1中查詢出來的值" }
使用java RestHighLevelClient
代碼參考如下:
@Autowired private RestHighLevelClient restHighLevelClient; public Result<GoodsDTo> scrollSearch(...查詢參數){ BoolQueryBuilder queryBuilder.te = QueryBuilders.boolQuery(); //添加自己的搜索條件.... queryBuilder.must(QueryBuilders.termQuery("type", "商品所屬分類); queryBuilder.must(QueryBuilders.matchQuery("name", "商品名稱"); //搜索 SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource(); searchSourceBuilder.query(queryBuilder); //排序 searchSourceBuilder.sort(SortBuilders.fieldSort("order").order(SortOrder.DESC)); //搜索結果 SearchResponse searchResponse = null; //根據實際情況,判斷是多次調用還是一次while遍歷查詢全部 if (StringUtils.isBlank("scrollId")) { //首屏 searchSourceBuilder.size("每次查詢的條數"); SearchRequest searchRequest = new SearchRequest(); searchRequest.indices("索引名").source(searchSourceBuilder); searchRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime))); searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); } else { //后續根據上次的id滾動 SearchScrollRequest searchScrollRequest = new SearchScrollRequest("scrollId"); searchScrollRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime))); searchResponse = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT); } SearchHit[] hits = searchResponse.getHits().getHits(); //根據業務需求,處理搜索結果 GoodsDTO result= handleSearchData(hits); //scrollId,往下滾動需要使用 String scrollId = searchResponse.getScrollId(); return Result.succcess(result); }
2:使用search after
滿足實時獲取下一頁的文檔信息,search_after 分頁的方式是根據上一頁的最后一條數據來確定下一頁的位置,同時在分頁請求的過程中,如果有索引數據的增刪改,這些變更也會實時的反映到游標上,這種方式是在es-5.X之后才提供的。為了找到每一頁最后一條數據,每個文檔的排序字段必須有一個全局唯一值使用 _id 就可以了。
API說明:
GET /book/_search { "query": {"match_all": {}}, "size": 2, "sort": [{"_id": "desc"}] } GET /book/_search { "query": {"match_all": {}}, "size": 2, "search_after": [3], "sort": [{"_id": "desc"}] }
下一頁的數據依賴上一頁的最后一條的信息 所以不能跳頁
使用java RestHighLevelClient
代碼參考如下:
@Autowired private RestHighLevelClient restHighLevelClient; public Result<GoodsDTo> searchAfter(...查詢參數){ SearchRequest searchRequest = new SearchRequest(index); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(...搜索條件); searchSourceBuilder.size(1000); searchSourceBuilder.sort("_id", SortOrder.ASC); searchSourceBuilder.searchAfter("上一頁最后一條數據的id"); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] hits = searchResponse.getHits().getHits(); //根據業務需求,處理搜索結果 GoodsDTO result= handleSearchData(hits); return Result.succcess(result); }
到此,關于“如何解決ES深度分頁問題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。