Elasticsearch分頁解決方案

Elasticsearch分頁解決方案

一、命令的方式做分頁

1、常見的分頁方式:from+size

elasticsearch默認採用的分頁方式是from+size的形式,但是在深度分頁的情況下,這種使用方式的效率是非常低的,比如from=5000,size=10,es需要在各個分片上匹配排序並得到5000*10條有效數據,然後在結果集中取最後10條數據返回。除了會遇到效率上的問題,還有一個無法解決的問題是es目前支持最大的skip值是max_result_window默認爲10000,也就是說當from+size > max_result_window時,es將返回錯誤。

解決方案:

        問題描述:比如當客戶線上的es數據出現問題,當分頁到幾百頁的時候,es無法返回數據,此時爲了恢復正常使用,我們可以採用緊急規避的方式,就是將max_result_window的值調至50000。

 

curl -XPUT "127.0.0.1:9200/custm/_settings" -d 
'{ 
    "index" : { 
        "max_result_window" : 50000 
    }
}'

對於上面這種解決方案只是暫時解決問題,當es的使用越來越多時,數據量越來越大,深度分頁的場景越來越複雜時,可以使用另一種分頁方式scroll。

 

在分佈式系統中深度分頁

理解爲什麼深度分頁是有問題的,我們可以假設在一個有 5 個主分片的索引中搜索。 當我們請求結果的第一頁(結果從 1 到 10 ),每一個分片產生前 10 的結果,並且返回給 協調節點 ,協調節點對 50 個結果排序得到全部結果的前 10 個。

現在假設我們請求第 1000 頁—​結果從 10001 到 10010 。所有都以相同的方式工作除了每個分片不得不產生前10010個結果以外。 然後協調節點對全部 50050 個結果排序最後丟棄掉這些結果中的 50040 個結果。

可以看到,在分佈式系統中,對結果排序的成本隨分頁的深度成指數上升。這就是 web 搜索引擎對任何查詢都不要返回超過 1000 個結果的原因。

 

2、scroll方式

爲了滿足深度分頁的場景,es提供了scroll的方式進行分頁讀取。原理上是對某次查詢生成一個遊標scroll_id,後續的查詢只需要根據這個遊標去取數據,知道結果集中返回的hits字段爲空,就表示遍歷結束。Scroll的作用不是用於實時查詢數據,因爲它會對es做多次請求,不肯能做到實時查詢。它的主要作用是用來查詢大量數據或全部數據。

使用scroll,每次只能獲取一頁的內容,然後會返回一個scroll_id。根據返回的這個scroll_id可以不斷地獲取下一頁的內容,所以scroll並不適用於有跳頁的情景

使用curl進行深度分頁讀取過程如下:

1、 先獲取第一個scroll_id,url參數包括/index/type和scroll,scroll字段指定了scroll_id的有效生存時間,過期後會被es自動清理。

[root@master ~]# curl -H "Content-Type: application/json" -XGET '192.168.200.100:9200/chuyun/_search?pretty&scroll=2m' -d'
{"query":{"match_all":{}}, "sort": ["_doc"]}'

2、在遍歷時候,拿到上一次遍歷中的_scroll_id,然後帶scroll參數,重複上一次的遍歷步驟,直到返回的數據爲空,表示遍歷完成。
每次都要傳參數scroll,刷新搜索結果的緩存時間,另外不需要指定index和type(不要把緩存的時時間設置太長,佔用內存)後續查詢:

curl -H "Content-Type: application/json" -XGET '192.168.200.100:9200/_search/scroll?pretty'  -d'
{
    "scroll" : "2m", 
    "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAABWFm43cDd3eERJVHNHMHJzSlNkajdPUHcAAAAAAAAAVxZuN3A3d3hESVRzRzByc0pTZGo3T1B3AAAAAAAAAFsWazlvUFptQnNTdXlmNmZRTl80cVdCdwAAAAAAAABVFm43cDd3eERJVHNHMHJzSlNkajdPUHcAAAAAAAAAWhZrOW9QWm1Cc1N1eWY2ZlFOXzRxV0J3" 
}'

 

 

3、scroll的刪除

刪除所有scroll_id

curl -XDELETE 192.168.200.100:9200/_search/scroll/_all

 

指定scroll_id刪除:

curl -XDELETE 192.168.200.100:9200/_search/scroll -d 
'{"scroll_id" : ["cXVlcnlBbmRGZXRjaDsxOzg3OTA4NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7"]}'

3、 search_after 的方式

使用search_after必須要設置from=0。

這裏我使用_id作爲唯一值排序。

我們在返回的最後一條數據裏拿到sort屬性的值傳入到search_after。

scroll的方式,官方不建議用於實時的請求(一般用於數據導出),因爲每一個scroll_id不僅會佔用大量的資源,而且會生成歷史快照,對於數據的變更不會反映到快照上。而search_after分頁的方式是根據上一頁的最後一條數據來確定下一頁的位置,同時再分頁請求的過程中,如果有索引數據的增刪改查,這些變更也會實時的反映到遊標上。但是需要注意,因爲每一頁的數據依賴於上一頁的最後一條數據,所以沒法跳頁請求。

爲了找到每一頁最後一條數據,每個文檔那個必須有一個全局唯一值,官方推薦使用_uuid作爲全局唯一值,當然在業務上的id也可以。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章