ES 分頁查詢

from+size分頁


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

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

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

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

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

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

兩種方式,1. 使用滾動API;2. 直接設置[index.max_result_window]參數。

curl -XPUT http://127.0.0.1:9200/my_index/_settings -d '{ "index" : { "max_result_window" : 500000}}'

my_index 更換爲要修改默認參數值的索引,後面的數值也可以自己設置,比如數據量爲兩萬多並且不會發生大的數量上的變化,可以把值設置爲30000。
如果是在Kibana控制面板裏面,則執行下面這段:

PUT my_index/_settings
{
  "index":{
    "max_result_window":500000
  }
}

 ElasticSearch實際上更適合作爲一個搜索的引擎,像這種分頁查詢遍歷查詢,實際上不是非常合適的。並且數值設置過大,會對機器造成壓力,可能造成內存溢出等錯誤。

scroll深分頁


ES爲了避免深分頁,不允許使用分頁(from&size)查詢10000條以後的數據,因此如果要查詢第10000條以後的數據,要使用ES提供的 scroll(遊標) 來查詢

可以把 scroll 理解爲關係型數據庫裏的 cursor,因此,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還好

 

具體實例

1、初始化

        請求

注意要在URL中的search後加上scroll=1m,不能寫在request body中,其中1m表示這個遊標要保持開啓1分鐘

可以指定size大小,就是每次回傳幾筆數據,當回傳到沒有數據時,仍會返回200成功,只是hits裡的hits會是空list

在初始化時除了回傳_scroll_id,也會回傳前100筆(假設size=100)的數據

request body和一般搜索一樣,因此可以說在初始化的過程中,除了加上scroll設置遊標開啓時間之外,其他的都跟一般的搜尋沒有兩樣 (要設置查詢條件,也會回傳前size筆的數據)

POST 127.0.0.1:9200/my_index/_search?scroll=1m
{
    "query":{
        "range":{
            "createTime": {
                "gte": 1522229999999
            }
        }
    },
    "size": 1000
}


返回結果

 

{
    "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAfv5-FjNOamF0Mk1aUUhpUnU5ZWNMaHJocWcAAAAAAH7-gBYzTmphdDJNWlFIaVJ1OWVjTGhyaHFnAAAAAAB-_n8WM05qYXQyTVpRSGlSdTllY0xocmhxZwAAAAAAdsJxFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbCcBZlZGUwSWpSVlJqeVJiN1dBWHNpUG1R",
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 84,
        "max_score": 1,
        "hits": [
            {
                "_index": "video1522821719",
                "_type": "doc",
                "_id": "84056",
                "_score": 1,
                "_source": {
                    "title": "三個院子",
                    "createTime": 1522239744000
                }
            }
            ....99 data
        ]
    }
}

 

2、遍歷數據

    請求

使用初始化返回的_scroll_id來進行請求,每一次請求都會繼續返回初始化中未讀完數據,並且會返回一個_scroll_id,這個_scroll_id可能會改變,因此每一次請求應該帶上上一次請求返回的_scroll_id

要注意返回的是_scroll_id,但是放在請求裡的是scroll_id,兩者拼寫上有不同

且每次發送scroll請求時,都要再重新刷新這個scroll的開啓時間,以防不小心超時導致數據取得不完整

POST 127.0.0.1:9200/_search/scroll?scroll=1m
{
    "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB"
}


返回結果

如果沒有數據了,就會回傳空的hits,可以用這個判斷是否遍歷完成了數據

{
    "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB",
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 84,
        "max_score": null,
        "hits": []
    }
}


優化scroll查詢

在一般場景下,scroll通常用來取得需要排序過後的大筆數據,但是有時候數據之間的排序性對我們而言是沒有關係的,只要所有數據都能取出來就好,這時能夠對scroll進行優化

初始化

使用_doc去sort得出來的結果,這個執行的效率最快,但是數據就不會有排序,適合用在只想取得所有數據的場景
 

POST 127.0.0.1:9200/my_index/_search?scroll=1m
{
    "query": {
        "match_all" : {}
    },
    "sort": [
        "_doc"
        ]
    }
}


清除scroll

雖然我們在設置開啓scroll時,設置了一個scroll的存活時間,但是如果能夠在使用完順手關閉,可以提早釋放資源,降低ES的負擔

DELETE 127.0.0.1:9200/_search/scroll
{
    "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB"
}


 

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