ElasticSearch第3篇 大數(shù)據(jù)處理3大問題(“10000條”問題解決方案、hits total值統(tǒng)計總數(shù)不精確解決方案楣号、大數(shù)據(jù)深度分頁性能問題3種優(yōu)化方案)

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

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

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

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

  • 癥狀:調(diào)用search()方法什往,可能查詢到的結果有20000條(count()方法統(tǒng)計得出)扳缕,ES也返回有10000條數(shù)據(jù)匹配。
{
    "took": 101,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 10000, //這里的統(tǒng)計結果不準别威,解決的就是這里的問題
            "relation": "gte"
        },
        "max_score": 1.0342529,
        "hits": [
            ......
    }
}
  • 緣由:ES團隊挑選一個不大不小的數(shù)作為閾值躯舔,處于性能和業(yè)務考慮,畢竟用戶基本沒耐心看數(shù)萬條之后的數(shù)據(jù)省古。
  • 解決:添加track_total_hits為true即可粥庄。
$params = [
    'index' => 'performance_test',
    'body'  => [
        'query' => [
            'match' => [
                'content' => '的'
            ]
        ],
        'track_total_hits' => true
    ]
];

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

大數(shù)據(jù)深度分頁性能問題

  • 極簡概括:在大數(shù)據(jù)情況下,查詢很多頁后的數(shù)據(jù)豺妓,ES響應速度會變慢甚至崩潰惜互。
  • 問題由來:假設億級數(shù)據(jù),要查詢某頁(頁數(shù)很大)之后的數(shù)據(jù)琳拭,ES底層就需要把前面很多頁的數(shù)據(jù)都要過一遍才能定位到指定頁训堆,這是一個巨大的開銷。所以大數(shù)據(jù)深度分頁一般不推薦使用from + size的傳統(tǒng)分頁方式白嘁。也算是一類業(yè)界難題坑鱼。
  • 測試:花了3個小時向ES插入了1.09億條中文數(shù)據(jù),實測每頁顯示2條數(shù)據(jù)权薯,翻頁到2000萬頁姑躲,效果如下:
深度分頁會把內(nèi)存干爆睡扬,導致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(業(yè)務需求優(yōu)化)

從業(yè)務需求源頭限制深度分頁卖怜。
例如某度搜索,深度分頁也就50~76頁是最后一頁(甚至不讓用戶從小頁碼直接跳轉大頁碼)阐枣,某寶搜索最大100頁马靠。
這個信息自然無法全部匯集。它們的定位不是要匯聚更全的信息蔼两,而是找出最精準的(或者金主爸爸打錢)數(shù)據(jù)甩鳄。
人為的也幾乎沒有耐心看完那么多頁的詞條。
可以說深度分頁并非適合所有業(yè)務場景额划,而是要做權衡(說人話就是要和產(chǎn)品經(jīng)理溝通以上文案)妙啃。

方案2 (Scroll API)

  • 輔助理解:類比愚公移山。操作對象太大俊戳,那就每次少量的處理揖赴,然后不停的分批迭代。這和分頁的分批處理思想相似抑胎,不過不用手動處理分頁問題燥滑。
  • 優(yōu)點:允許處理超大規(guī)模的數(shù)據(jù)集。
  • 缺點:不支持頁跳轉(第M頁跳轉N頁)阿逃,只支持遞增頁和遞減頁铭拧。scroll查詢的相應數(shù)據(jù)是非實時的,如果遍歷過程是恃锉,其它請求要返回的數(shù)據(jù)進行了寫操作搀菩,是查詢不到最新的結果的。
$params = [
    'index' => 'performance_test',
    'scroll' => '1m', //用于設置滾動上下文的存活時間破托,1m是一分鐘秕磷,過了這個時間,scroll_id參數(shù)就失效了炼团,有這個id,好比創(chuàng)建了一個專門的任務疏尿,讓ES去處理這件事
    'size' => 2,
    'body'  => [
        'query' => [
            'match' => [
                'content' => '袁隆平' //要搜索整個文檔中瘟芝,包含袁隆平的
            ]
        ]
    ]
];

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


$scroll_id = $response['_scroll_id'];

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

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

    // 處理數(shù)據(jù),這里只做打印
    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 推薦方案)

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

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


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


/**
 * @function SearchAfter方法封裝
 * @param   $client   object      ElasticSearch對象
 * @param   $params   array       search()所需要的參數(shù)
 * @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;
}


//模擬處理第二頁的數(shù)據(jù)
$response = searchAfter($client, $params, $response);
dd($response->asArray());
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孔庭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子材蛛,更是在濱河造成了極大的恐慌圆到,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仰税,死亡現(xiàn)場離奇詭異构资,居然都是意外死亡,警方通過查閱死者的電腦和手機陨簇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門吐绵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人河绽,你說我怎么就攤上這事己单。” “怎么了耙饰?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵纹笼,是天一觀的道長。 經(jīng)常有香客問我苟跪,道長廷痘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任件已,我火速辦了婚禮笋额,結果婚禮上,老公的妹妹穿的比我還像新娘篷扩。我一直安慰自己兄猩,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枢冤,像睡著了一般鸠姨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淹真,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天讶迁,我揣著相機與錄音,去河邊找鬼趟咆。 笑死添瓷,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的值纱。 我是一名探鬼主播鳞贷,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼虐唠!你這毒婦竟也來了搀愧?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤疆偿,失蹤者是張志新(化名)和其女友劉穎咱筛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杆故,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡迅箩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了处铛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饲趋。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖撤蟆,靈堂內(nèi)的尸體忽然破棺而出奕塑,到底是詐尸還是另有隱情,我是刑警寧澤家肯,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布龄砰,位于F島的核電站,受9級特大地震影響讨衣,放射性物質發(fā)生泄漏换棚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一反镇、第九天 我趴在偏房一處隱蔽的房頂上張望圃泡。 院中可真熱鬧,春花似錦愿险、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽风秤。三九已至,卻和暖如春扮叨,著一層夾襖步出監(jiān)牢的瞬間缤弦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工彻磁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碍沐,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓衷蜓,卻偏偏與公主長得像累提,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子磁浇,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容