ElasticSearch第3篇 大數據處理3大問題(“10000條”問題解決方案、hits total值統計總數不精確解決方案、大數據深度分頁性能問題3種優化方案)

来源:https://www.cnblogs.com/phpphp/p/18327848
-Advertisement-
Play Games

“10000條”問題(個人稱謂) 癥狀: 在數據量不大的情況下,可能還會使用from + size的傳統分頁方式,但是數量受限,只能取前10000條的數據。 緣由:ES限值10000條,是ES團隊挑選一個不大不小的數作為閾值,為了避免深度分頁的策略。 調整:max_result_window 用於控 ...


“10000條”問題(個人稱謂)

  • 癥狀: 在數據量不大的情況下,可能還會使用from + size的傳統分頁方式,但是數量受限,只能取前10000條的數據。
  • 緣由:ES限值10000條,是ES團隊挑選一個不大不小的數作為閾值,為了避免深度分頁的策略。
  • 調整:max_result_window 用於控制在搜索查詢中可以檢索到的最大文檔數,是有符號int類型,最大可設置231 - 1,調大可以,但隨著數據量(不是max_result_window 值)增加會有性能問題。
返回bool
$params = [
    'index' => 'performance_test',
    'body'  => [
        'index' => [
            'max_result_window' => 2147483647 //用於控制在搜索查詢中可以檢索到的最大文檔數,有符號int類型,最大可設置2^31 - 1,但隨著數據量增加會有性能問題。
        ]
    ]
];

$response = $client->indices()->putSettings($params);
dd($response->asBool());

hits total值統計總數不精確解決方案(另一種“10000條”問題)

  • 癥狀:調用search()方法,可能查詢到的結果有20000條(count()方法統計得出),ES也返回有10000條數據匹配。
{
    "took": 101,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 10000, //這裡的統計結果不准,解決的就是這裡的問題
            "relation": "gte"
        },
        "max_score": 1.0342529,
        "hits": [
            ......
    }
}
  • 緣由:ES團隊挑選一個不大不小的數作為閾值,處於性能和業務考慮,畢竟用戶基本沒耐心看數萬條之後的數據。
  • 解決:添加track_total_hits為true即可。
$params = [
    'index' => 'performance_test',
    'body'  => [
        'query' => [
            'match' => [
                'content' => '的'
            ]
        ],
        'track_total_hits' => true
    ]
];

$response = $client->search($params);
dd($response->asArray());

大數據深度分頁性能問題

  • 極簡概括:在大數據情況下,查詢很多頁後的數據,ES響應速度會變慢甚至崩潰。
  • 問題由來:假設億級數據,要查詢某頁(頁數很大)之後的數據,ES底層就需要把前面很多頁的數據都要過一遍才能定位到指定頁,這是一個巨大的開銷。所以大數據深度分頁一般不推薦使用from + size的傳統分頁方式。也算是一類業界難題。
  • 測試:花了3個小時向ES插入了1.09億條中文數據,實測每頁顯示2條數據,翻頁到2000萬頁,效果如下:
深度分頁會把記憶體乾爆,導致java程式OutOfMemoryError,ES進程被終止。
[2024-07-27T09:01:39,206][INFO ][o.e.c.r.a.AllocationService] [localhost.localdomain] current.health="YELLOW" message="Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[performance_test][0]]])." previous.health="RED" reason="shards started [[performance_test][0]]"
[2024-07-27T09:01:58,487][INFO ][o.e.m.j.JvmGcMonitorService] [localhost.localdomain] [gc][21] overhead, spent [331ms] collecting in the last [1.1s]
[2024-07-27T09:02:00,495][INFO ][o.e.m.j.JvmGcMonitorService] [localhost.localdomain] [gc][23] overhead, spent [334ms] collecting in the last [1s]
[2024-07-27T09:02:02,674][WARN ][o.e.m.j.JvmGcMonitorService] [localhost.localdomain] [gc][24] overhead, spent [2s] collecting in the last [2.1s]
[2024-07-27T09:02:04,181][WARN ][o.e.m.j.JvmGcMonitorService] [localhost.localdomain] [gc][25] overhead, spent [1.2s] collecting in the last [1.5s]
[2024-07-27T09:02:07,837][WARN ][o.e.m.j.JvmGcMonitorService] [localhost.localdomain] [gc][26] overhead, spent [3.5s] collecting in the last [1.8s]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to data/java_pid20168.hprof ...

索引與映射結構(下文要用)

$params = [
    'index' => 'performance_test',
    'body'  => [
        'settings' => [
            'analysis' => [
                'analyzer' => [
                    'ik_analyzer' => [
                        'type'      => 'ik_max_word',
                    ],
                ],
            ],
        ],
        'mappings' => [
            'properties' => [
                'id' => [
                    'type'     => 'integer',
                ],
                'content' => [
                    'type'     => 'text',
                    'analyzer' => 'ik_analyzer',
                ],
            ],
        ],
    ],
];

方案1(業務需求優化)

從業務需求源頭限制深度分頁。
例如某度搜索,深度分頁也就50~76頁是最後一頁(甚至不讓用戶從小頁碼直接跳轉大頁碼),某寶搜索最大100頁
這個信息自然無法全部彙集。它們的定位不是要匯聚更全的信息,而是找出最精準的(或者金主爸爸打錢)數據。
人為的也幾乎沒有耐心看完那麼多頁的詞條。
可以說深度分頁並非適合所有業務場景,而是要做權衡(說人話就是要和產品經理溝通以上文案)。

方案2 (Scroll API)

  • 輔助理解:類比愚公移山。操作對象太大,那就每次少量的處理,然後不停的分批迭代。這和分頁的分批處理思想相似,不過不用手動處理分頁問題。
  • 優點:允許處理超大規模的數據集。
  • 缺點:不支持頁跳轉(第M頁跳轉N頁),只支持遞增頁和遞減頁。scroll查詢的相應數據是非實時的,如果遍歷過程是,其它請求要返回的數據進行了寫操作,是查詢不到最新的結果的。
$params = [
    'index' => 'performance_test',
    'scroll' => '1m', //用於設置滾動上下文的存活時間,1m是一分鐘,過了這個時間,scroll_id參數就失效了,有這個id,好比創建了一個專門的任務,讓ES去處理這件事
    'size' => 2,
    'body'  => [
        'query' => [
            'match' => [
                'content' => '袁隆平' //要搜索整個文檔中,包含袁隆平的
            ]
        ]
    ]
];

$response = $client->search($params);
dump($response->asArray()); //常規的處理


$scroll_id = $response['_scroll_id'];

while (true) {
    $response = $client->scroll([
        'scroll_id' => $scroll_id,
        'scroll'    => '1m'
    ]);

    // 檢查是否有數據返回
    if (empty($response['hits']['hits'])) {
        break;
    }

    // 處理數據,這裡只做列印
    foreach ($response['hits']['hits'] as $hit) {
        dump($hit['_source']);
    }

    // 更新 scroll ID
    $scroll_id = $response['_scroll_id'];
}

// 清理Scroll請求,釋放資源
$client->clearScroll([
    'scroll_id' => $scroll_id
]);

方案3 (Search After 推薦方案)

  • 輔助理解:上一頁的最後一條數據,作為當前頁的起始偏移量。操作對象太大,那就每次少量的處理,然後不停的迭代,這和分頁的分批處理思想相似。
  • 優點:ES針對深度分頁的新解決方案,不會有太多的性能問題。
  • 缺點:必須指定排序欄位,否則起始偏移量參考系參數無法使用。
$params = [
    'index' => 'performance_test',
    'body'  => [
        'query' => [
            'match_all' => new stdClass()
        ],
        'sort'  => [
            ['id' => 'asc']
        ],
        'size'  => 2 //這個排序是必須的,不一定是id,但通常是id,排序是為了去上一條數據的時候定位不會錯亂
    ]
];

//發起第一次查詢,獲取第一頁結果
$response = $client->search($params);


//模擬處理第一頁的結果
foreach ($response['hits']['hits'] as $hit) {
    //模擬處理
    dump($hit['_source']['content']);
}


/**
 * @function SearchAfter方法封裝
 * @param   $client   object      ElasticSearch對象
 * @param   $params   array       search()所需要的參數
 * @param   $response object|null search()方法查詢出來的結果
 * @return  object
 */
function searchAfter($client, $params, $response) {
    if(is_object($response)) {
        $response = $response->asArray();
    }

    if(empty($response['hits']['hits'])) {
        return null;
    }

    $last_data = end($response['hits']['hits']);
    //在其餘查詢條件不變的情況下,只修改search_after值。
    $params['body']['search_after'] = $last_data['sort'];
    //然後再次查詢
    $response = $client->search($params);
    return $response;
}


//模擬處理第二頁的數據
$response = searchAfter($client, $params, $response);
dd($response->asArray());

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在現代軟體開發和部署中,Docker容器已成為一種流行的技術。然而,隨著容器的廣泛使用,數據保護和遷移也變得至關重要。本文將詳細介紹如何備份和遷移Docker容器,確保你的應用和數據在任何時候都是安全的。 一、為什麼需要備份和遷移Docker容器? 在某些情況下,你可能需要備份和遷移Docker容器 ...
  • 書接上文,在一個正常的事務複製環境中,如果發生了資料庫還原,事務複製會不會出問題,出問題之後又如何恢復,如果在不刪除訂閱發佈重建的情況下,如何在現有基礎上修複事務複製的異常,這個問題可以分為兩部分看: 1,如果publisher資料庫發生了還原操作,事務複製會出現什麼異常,該如何恢復? 2,如果是s ...
  • Vue 的 Keep-Alive 組件是用於緩存組件的高階組件,可以有效地提高應用性能。它能夠使組件在切換時仍能保留原有的狀態信息,並且有專門的生命周期方便去做額外的處理。該組件在很多場景非常有用,比如: · tabs 緩存頁面 · 分步表單 · 路由緩存 在 Vue 中,通過 KeepAlive ...
  • 上次向大家分享了論文圖譜項目Awesome-Graphs的介紹文章,這次我們就拿圖計算系統的奠基文章Pregel開篇,沿著論文圖譜的主線,對圖計算系統的論文內容進行解讀。 ...
  • 1. 事物的四大特性 事務是邏輯上的一組操作,要麼都執行,要麼都不執行 原子性(Atomicity):事務是最小的執行單位,不允許分割。事務的原子性確保動作要麼全部完成,要麼完全不起作用; 一致性(Consistency):執行事務前後,數據保持一致,例如轉賬業務中,無論事務是否成功,轉賬者和收款人 ...
  • GreatSQL 的刷新鎖 前言 因為運維小伙伴執行dump備份命令,導致資料庫卡住,很多會話都在waiting for table flush,基於這一故障,我對GreatSQL的刷新鎖進行了研究。感興趣的小伙伴請隨我一探究竟吧。 刷新鎖的癥狀 刷新鎖問題的主要癥狀是資料庫會進入嘎然而止的狀態,所 ...
  • 經過實測:1.09億的數據量進行中文檢索。ElasticSearch單機的檢索性能在0.005~5.6秒之間,此檢索速度可滿足95%的業務場景(註意:每條ES文檔平均65個漢字,數據源取自幾千本小說,大部分文檔在15~300個漢字之間,不然字數太多索引太大電腦存不下)。 前置文章 由於本文章的前置操 ...
  • 如何讓SQL Server像MySQL一樣擁有慢查詢日誌(Slow Query Log慢日誌) SQL Server一直以來被人詬病的一個問題是缺少了像MySQL的慢日誌功能,程式員和運維無法知道資料庫過去歷史的慢查詢語句。 因為SQLServer預設是不捕獲過去歷史的長時間阻塞的SQL語句,導致大 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...