Elasticsearch 分頁問題

Elasticsearch分頁一般有三種方式:

1.form和size的方式

2.Scroll api

3.search_after參數

 

from+size分頁

按照一般的查詢流程來說,如果我想查詢前10條數據:

    1 客戶端請求發給某個節點
    2 節點轉發給個個分片,查詢每個分片上的前10條
    3 結果返回給節點,整合數據,提取前10條
    4 返回給請求客戶端

該分頁方式可以通過from+size的方式來進行實現。
from定義了目標數據的偏移值,size定義當前返回的事件數目。

GET /fs/_search?pretty
{
  "from" : 0 , "size" : 10
}

GET /fs/_search?pretty
{
  "from" : 10 , "size" : 10
}

這種分頁方式只適合少量數據,因爲隨from增大,查詢的時間就會越大,而且數據量越大,查詢的效率指數下降

優點:from+size在數據量不大的情況下,效率比較高
缺點:在數據量非常大的情況下,from+size分頁會把全部記錄加載到內存中,這樣做不但運行速遞特別慢,而且容易讓es出現內存不足而掛掉

比如要取第5001頁的數據,在分頁的時候,elasticsearch需要首先在每一個節點上取出50020的數據,然後和每一個節點的所有數據進行排序,取出排序後在50010到50020的數據,然後返回。這樣隨着數據量的增大,每次分頁時排序的開銷會越來越大。

一般的分頁需求我們可以使用form和size的方式實現,但是這種分頁方式在深度分頁的場景下應該是要避免使用的。深度分頁會隨着請求的頁次增加,所消耗的內存和時間的增長也是成比例的增加,爲了避免深度分頁產生的問題,elasticsearch從2.0版本開始,增加了一個限制:

index.max_result_window =10000

 

scroll深分頁

爲了解決上面的問題,elasticsearch提出了一個scroll滾動的方式,這個滾動的方式原理就是通過每次查詢後,返回一個scroll_id。根據這個scroll_id 進行下一頁的查詢。可以把這個scroll_id理解爲通常關係型數據庫中的遊標。

scroll就是維護了當前索引段的一份快照信息–緩存(這個快照信息是你執行這個scroll查詢時的快照)

可以把 scroll 分爲初始化和遍歷兩步:

1、初始化時將所有符合搜索條件的搜索結果緩存起來,可以想象成快照;

GET fs/_search?scroll=3m
{
  "query": {"match_all": {}},
   "size": 3
}

初始化的時候就像是普通的search一樣
其中的scroll=3m代表當前查詢的數據緩存3分鐘
Size:3 代表當前查詢3條數據

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

scroll雖然能夠解決from size帶來的問題,但是由於它代表的是某個時刻的snapshot,不適合做實時查詢;且由於scroll後接超時時間,頻繁地發起scroll請求,也會出現一系列問題。

 

search_after參數

search_after: 性能優秀,類似於優化後的分頁查詢,歷史條件過濾掉數據。

檢索第一頁的查詢如下所示:

 POST twitter/_search
    {
        "size": 10,
        "query": {
            "match" : {
                "title" : "elasticsearch"
            }
        },
        "sort": [
            {"date": "asc"},
            {"_id": "desc"}
        ]
    }

    每個文檔具有一個唯一值的字段應該用作排序規範的仲裁器。否則,具有相同排序值的文檔的排序順序將是未定義的。建議的方法是使用字段_id,它肯定包含每個文檔的一個唯一值。

上面的請求會爲每一個文檔返回一個包含sort排序值的數組。這些sort排序值可以被用於 search_after 參數裏以便抓取下一頁的數據。比如,我們可以使用最後的一個文檔的sort排序值,將它傳遞給 search_after 參數:

 GET twitter/_search
    {
        "size": 10,
        "query": {
            "match" : {
                "title" : "elasticsearch"
            }
        },
        "search_after": [1463538857, "654323"],
        "sort": [
            {"date": "asc"},
            {"_id": "desc"}
        ]
    }

    當我們使用 search_after 參數的時候,from參數必須被設置成 0 或 -1 (當然你也可以不設置這個from參數)。

    search_after缺點是不能夠隨機跳轉分頁,只能是一頁一頁的向後翻,並且需要至少指定一個唯一不重複字段來排序。它與滾動API非常相似,但與它不同,search_after參數是無狀態的,它始終針對最新版本的搜索器進行解析。因此,排序順序可能會在步行期間發生變化,具體取決於索引的更新和刪除。

 


 

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