溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決ES深度分頁問題

發(fā)布時間:2021-10-12 11:19:58 來源:億速云 閱讀:855 作者:iii 欄目:編程語言

這篇文章主要介紹“如何解決ES深度分頁問題”,在日常操作中,相信很多人在如何解決ES深度分頁問題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何解決ES深度分頁問題”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

ES深度分頁問題:

ES 默認(rèn)采用的分頁方式是 from+ size 的形式,類似于MySQL的分頁offset+limit。當(dāng)請求數(shù)據(jù)量比較大時,Elasticsearch會對分頁做出限制,因為此時性能消耗會很大。例如查詢1000條數(shù)據(jù),假設(shè)我們有5個分片,那么每個shard都需要返回1000條數(shù)據(jù)給 coordinating node,而 coordinating node 需要接收 5*1000 條數(shù)據(jù),進(jìn)行排序后返回1000條數(shù)據(jù)給客戶端。即使每條數(shù)據(jù)只有 _doc _id 和 _score,這數(shù)據(jù)量也很大了,如果請請求量很大的情況下,很容易造成ES的OOM。ES中有個設(shè)置index.max_result_window ,默認(rèn)是10000條數(shù)據(jù),如果分頁的數(shù)據(jù)超過第1萬條,就拒絕返回結(jié)果了。如果集群配置比較好,查詢請求量不是特別大,可以適當(dāng)?shù)姆糯筮@個參數(shù)。

解決方案:

1:使用scroll遍歷

scroll 分為初始化和遍歷兩步,初始化時將所有符合搜索條件的搜索結(jié)果緩存起來,可以想象成快照,在遍歷時,從這個快照里取數(shù)據(jù),也就是說,在初始化后對索引插入、刪除、更新數(shù)據(jù)都不會影響遍歷結(jié)果。因此,scroll 并不適合用來做實時搜索,而更適用于后臺批處理任務(wù)等

API說明:

1)初始化

POST /book/_search?scroll=1m&size=2
{
"query": { "match_all": {}}
}
  1. 遍歷

GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "步驟1中查詢出來的值"
}

使用java RestHighLevelClient代碼參考如下:

@Autowired
private RestHighLevelClient restHighLevelClient;

public Result<GoodsDTo>  scrollSearch(...查詢參數(shù)){
     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));
     //搜索結(jié)果
     SearchResponse searchResponse = null;
     //根據(jù)實際情況,判斷是多次調(diào)用還是一次while遍歷查詢?nèi)?
  	if (StringUtils.isBlank("scrollId")) {
            //首屏
            searchSourceBuilder.size("每次查詢的條數(shù)");
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("索引名").source(searchSourceBuilder);
            searchRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime)));
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
     } else {
            //后續(xù)根據(jù)上次的id滾動
            SearchScrollRequest searchScrollRequest = new SearchScrollRequest("scrollId");
            searchScrollRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime)));
            searchResponse = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
     }
        
     SearchHit[] hits = searchResponse.getHits().getHits();
     //根據(jù)業(yè)務(wù)需求,處理搜索結(jié)果
     GoodsDTO result= handleSearchData(hits);
     //scrollId,往下滾動需要使用
     String scrollId = searchResponse.getScrollId();
     return Result.succcess(result);
}

2:使用search after

滿足實時獲取下一頁的文檔信息,search_after 分頁的方式是根據(jù)上一頁的最后一條數(shù)據(jù)來確定下一頁的位置,同時在分頁請求的過程中,如果有索引數(shù)據(jù)的增刪改,這些變更也會實時的反映到游標(biāo)上,這種方式是在es-5.X之后才提供的。為了找到每一頁最后一條數(shù)據(jù),每個文檔的排序字段必須有一個全局唯一值使用 _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"}]
}

下一頁的數(shù)據(jù)依賴上一頁的最后一條的信息 所以不能跳頁

使用java RestHighLevelClient代碼參考如下:

@Autowired
private RestHighLevelClient restHighLevelClient;

public Result<GoodsDTo>  searchAfter(...查詢參數(shù)){
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(...搜索條件);
        searchSourceBuilder.size(1000);
        searchSourceBuilder.sort("_id", SortOrder.ASC);
        searchSourceBuilder.searchAfter("上一頁最后一條數(shù)據(jù)的id");
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
         //根據(jù)業(yè)務(wù)需求,處理搜索結(jié)果
         GoodsDTO result= handleSearchData(hits);
         return Result.succcess(result);
}

到此,關(guān)于“如何解決ES深度分頁問題”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI