欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Elasticsearch進行深度分頁的詳細指南(避免踩坑+報錯)

 更新時間:2025年04月15日 09:56:06   作者:浪浪山老周  
這篇文章主要為大家詳細介紹了使用Elasticsearch進行深度分頁時會員踩的坑以及報錯的相關(guān)解決方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

一、問題復(fù)現(xiàn):為何查詢會觸發(fā)「Result window is too large」

當(dāng)我們在 Elasticsearch 中使用傳統(tǒng)分頁參數(shù) from 和 size 時,若 from + size > 10000,會直接觸發(fā)如下異常:

{
  "error": {
    "root_cause": [{
      "type": "illegal_argument_exception",
      "reason": "Result window is too large, from + size must be <= 10000"
    }]
  }
}

??根本原因??:

Elasticsearch 默認(rèn)限制單次查詢返回的文檔總數(shù)不超過 10,000 條(即 index.max_result_window 參數(shù))。當(dāng)進行深度分頁(如查詢第 10001-10100 條數(shù)據(jù))時,協(xié)調(diào)節(jié)點需要從所有分片中??先拉取前 10100 條數(shù)據(jù)??,再進行全局排序和截取,導(dǎo)致內(nèi)存和計算資源爆炸。

二、解決方案對比:哪種方案適合你的場景

方案原理優(yōu)點缺點適用場景
??調(diào)整 max_result_window??直接修改索引配置增大分頁窗口實現(xiàn)簡單,無需改代碼內(nèi)存風(fēng)險高,僅適合小數(shù)據(jù)量少量數(shù)據(jù)的分頁(≤10萬條)
Scroll API??通過快照機制保持查詢上下文,分批次拉取數(shù)據(jù)支持海量數(shù)據(jù)導(dǎo)出數(shù)據(jù)實時性差,資源消耗大批量導(dǎo)出/離線任務(wù)
??Search After??基于上一頁最后一個文檔的排序值作為游標(biāo),避免 from 累積性能最優(yōu),支持實時分頁必須定義全局排序字段C端實時分頁(如列表頁瀏覽)

三、方案詳解與代碼實現(xiàn)

1. 暴力擴容法:調(diào)整 max_result_window(不推薦)

??實現(xiàn)步驟??:

# 動態(tài)修改索引配置(需保留原有設(shè)置)
PUT /your_index/_settings?preserve_existing=true
{
  "index": {
    "max_result_window": "20000"  # 設(shè)置為更大的值
  }
}

核心問題??:

  • 官方明確警告此操作可能導(dǎo)致 ??OOM(內(nèi)存溢出)?? 和節(jié)點故障
  • 深度分頁時,協(xié)調(diào)節(jié)點仍需加載前 N 條數(shù)據(jù)到內(nèi)存,性能呈指數(shù)級下降
  • 僅適合臨時測試或數(shù)據(jù)量極小的場景(如后臺管理后臺導(dǎo)出 10 萬條數(shù)據(jù))

2.批量導(dǎo)出法:Scroll API(適合離線場景)

??實現(xiàn)原理??:

通過 scroll 參數(shù)創(chuàng)建快照上下文,后續(xù)請求通過 scroll_id 持續(xù)拉取數(shù)據(jù),避免重復(fù)計算排序。

??Java 代碼示例??:

public JSONArray scrollQuery(JSONObject params) {
    JSONArray result = new JSONArray();
    String scrollId = null;
    
    try {
        // 初始化滾動查詢(保持 10 分鐘快照)
        SearchRequest searchRequest = new SearchRequest("logs");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.size(1000);
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        
        searchRequest.source(sourceBuilder);
        searchRequest.scroll(TimeValue.timeValueMinutes(10));
        
        // 首次查詢獲取 scroll_id
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        scrollId = response.getScrollId();
        result.addAll(Arrays.asList(response.getHits().getHits()));
        
        // 持續(xù)拉取數(shù)據(jù)
        while (true) {
            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(TimeValue.timeValueMinutes(10));
            response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            
            if (response.getHits().getHits().length == 0) break;
            result.addAll(Arrays.asList(response.getHits().getHits()));
            scrollId = response.getScrollId();
        }
    } finally {
        // 清理上下文(必須操作)
        if (scrollId != null) {
            ClearScrollRequest clearRequest = new ClearScrollRequest();
            clearRequest.addScrollId(scrollId);
            client.clearScroll(clearRequest, RequestOptions.DEFAULT);
        }
    }
    return result;
}

??關(guān)鍵問題??:

  • 每次滾動需維護 scroll_id,內(nèi)存占用隨數(shù)據(jù)量增長
  • 數(shù)據(jù)快照版本可能導(dǎo)致查詢結(jié)果不一致(如文檔被更新或刪除)

3.實時分頁法:Search After(推薦方案)

??實現(xiàn)原理??:

通過記錄上一頁最后一個文檔的排序值(如時間戳或唯一ID),在下一次查詢時直接定位到該位置,??跳過無效數(shù)據(jù)掃描??。

??Java 代碼實現(xiàn)??:

java
public JSONObject searchData(JSONObject queryConditionsParam) {
    int pageSize = queryConditionsParam.getInt("pageSize");
    double[] searchAfter = null;
    
    // 提取游標(biāo)參數(shù)(上一頁最后一個文檔的排序值)
    if (queryConditionsParam.containsKey("search_after")) {
        JSONArray searchAfterArray = queryConditionsParam.getJSONArray("search_after");
        searchAfter = searchAfterArray.toDoubleArray();
    }

    SearchRequest searchRequest = new SearchRequest("my_log");
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

    // 關(guān)鍵配置:排序字段必須與 search_after 對應(yīng)
    sourceBuilder.sort("created_start_time", SortOrder.DESC);
    if (searchAfter != null) {
        sourceBuilder.searchAfter(searchAfter);
    }
    sourceBuilder.size(pageSize); // 無需設(shè)置 from 參數(shù)

    // 構(gòu)建查詢條件(示例:按日志ID過濾)
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    boolQueryBuilder.must(QueryBuilders.termQuery("log_id", queryConditionsParam.getInt("log_id")));
    // 其他復(fù)雜條件可在此追加...

    sourceBuilder.query(boolQueryBuilder);
    searchRequest.source(sourceBuilder);

    try {
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        return buildResult(response); // 封裝結(jié)果并返回游標(biāo)
    } catch (IOException e) {
        log.error("ES查詢失敗", e);
        throw new RuntimeException("查詢異常");
    }
}

// 結(jié)果封裝方法:提取游標(biāo)并返回下一頁參數(shù)
private JSONObject buildResult(SearchResponse response) {
    JSONObject result = new JSONObject();
    JSONArray hits = new JSONArray();
    double[] nextCursor = null;

    for (SearchHit hit : response.getHits()) {
        hits.add(new JSONObject(hit.getSourceAsString()));
        // 提取排序字段值作為下一頁游標(biāo)
        if (hit.getSortValues().length > 0) {
            nextCursor = Arrays.stream(hit.getSortValues())
                              .mapToDouble(Double::valueOf)
                              .toArray();
        }
    }

    result.put("data", hits);
    result.put("totalCount", response.getHits().getTotalHits().value);
    if (nextCursor != null) {
        result.put("search_after", nextCursor); // 返回游標(biāo)供下次查詢
    }
    return result;
}

??性能優(yōu)勢??:

??無深度分頁開銷??: 每次查詢僅獲取當(dāng)前頁數(shù)據(jù),避免全量數(shù)據(jù)掃描

??實時性保障??: 直接訪問最新數(shù)據(jù)快照,不受索引刷新影響

??資源消耗低??: 內(nèi)存占用與分頁大小線性相關(guān),而非與數(shù)據(jù)總量相關(guān)

四、方案選型決策樹

數(shù)據(jù)量 ≤10 萬條?? → 調(diào)整 max_result_window(快速實現(xiàn))

??需要全量導(dǎo)出?? → Scroll API(配合異步任務(wù))

??C端實時交互?? → Search After(最佳實踐)

五、避坑指南

1. 游標(biāo)失效場景??:

數(shù)據(jù)更新或刪除時,可能導(dǎo)致游標(biāo)失效(需結(jié)合業(yè)務(wù)場景評估)

避免在頻繁更新的字段上使用 search_after

2.分頁深度限制??:

即使使用 search_after,仍建議限制最大分頁深度(如最多 1000 頁),防止惡意請求

??3.監(jiān)控與告警??:

通過 Elasticsearch 的 _cat/indices 接口監(jiān)控分頁查詢頻率,設(shè)置閾值告警

六、總結(jié)

方案推薦指數(shù)適用階段
調(diào)整 max_result_window?☆☆☆☆早期驗證階段
Scroll API??☆☆☆臨時數(shù)據(jù)遷移/批量導(dǎo)出
Search After?????生產(chǎn)環(huán)境實時分頁

??終極建議: 在日志分析、用戶行為追蹤等場景中,結(jié)合 search_after + 時間范圍過濾 + 適當(dāng)?shù)木彺娌呗裕蓪崿F(xiàn)億級數(shù)據(jù)的高效分頁。立即升級你的分頁方案,告別 Result window is too large 報錯!

到此這篇關(guān)于Elasticsearch進行深度分頁的詳細指南(避免踩坑+報錯)的文章就介紹到這了,更多相關(guān)Elasticsearch深度分頁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java的主要特性學(xué)習(xí)總結(jié)

    java的主要特性學(xué)習(xí)總結(jié)

    在本篇文章里小編給大家分享了一篇關(guān)于java的主要特性學(xué)習(xí)總結(jié)內(nèi)容,有興趣的朋友們可以參考下。
    2020-05-05
  • 使用棧的迷宮算法java版代碼

    使用棧的迷宮算法java版代碼

    這篇文章主要為大家詳細介紹了使用棧的迷宮算法java版代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • eclipse輸出Hello World的實現(xiàn)方法

    eclipse輸出Hello World的實現(xiàn)方法

    這篇文章主要介紹了eclipse輸出Hello World的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java整合騰訊云短信發(fā)送實例代碼

    Java整合騰訊云短信發(fā)送實例代碼

    大家好,本篇文章主要講的是Java整合騰訊云短信發(fā)送實例代碼,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • java編譯時指定classpath的實現(xiàn)方法

    java編譯時指定classpath的實現(xiàn)方法

    在Java編程中,classpath是用于指定Java虛擬機在運行時查找類文件的路徑,本文主要介紹了java編譯時指定classpath的實現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • Java如何連接數(shù)據(jù)庫圖文教程

    Java如何連接數(shù)據(jù)庫圖文教程

    關(guān)于java數(shù)據(jù)庫的文章早已是非常多了,本文是對我個人過往學(xué)習(xí)java數(shù)據(jù)庫,理解及應(yīng)用java數(shù)據(jù)庫的一個總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java如何連接數(shù)據(jù)庫的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • java讀取文件字符集示例方法

    java讀取文件字符集示例方法

    這篇文章主要介紹了java讀取文件字符集的示例,需要的朋友可以參考下
    2014-02-02
  • Spring Bean實例的創(chuàng)建及構(gòu)造器的挑選

    Spring Bean實例的創(chuàng)建及構(gòu)造器的挑選

    這篇文章主要介紹了Spring Bean實例的創(chuàng)建及構(gòu)造器的挑選,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-04-04
  • 圖文講解IDEA中根據(jù)數(shù)據(jù)庫自動生成實體類

    圖文講解IDEA中根據(jù)數(shù)據(jù)庫自動生成實體類

    這篇文章主要以圖文講解IDEA中根據(jù)數(shù)據(jù)庫自動生成實體類,本文主要以Mysql數(shù)據(jù)庫為例,應(yīng)該會對大家有所幫助,如果有錯誤的地方,還望指正
    2023-03-03
  • springmvc接收json串,轉(zhuǎn)換為實體類List方法

    springmvc接收json串,轉(zhuǎn)換為實體類List方法

    今天小編就為大家分享一篇springmvc接收json串,轉(zhuǎn)換為實體類List方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08

最新評論