正確遍歷ElasticSearch索引

1:ElasticSearch的查詢過程html

2:由ES查詢模式引發的深度分頁問題java

3:如何正確遍歷索引中的數據數據庫


 

ElasticSearch的查詢過程c#

es的數據查詢分兩步:安全

第一步是的結果是獲取知足查詢條件的,分佈於各個shard上的_doc_id及對應_score;服務器

第二步是根據第一步獲取的全部的_doc_id,去各個shard上獲取數據明細,合併返回客戶端。elasticsearch

 

在第一步的查詢中,es執行了一個相似map-reduce的查詢模式:在各個shard上執行一樣的查詢,獲取一樣大小的數據(from+size),而後將各個 shard查詢結果的_doc_id,_score返回給接收查詢請求的節點,最終進行一次彙總。注意這裏傳輸數據的數量是from+size,而不只僅是size大小。ide

 


 

 

由ES查詢模式引發的深度分頁問題性能

經過ES的查詢過程咱們已經能夠看出問題,對大數據量的Index進行遍歷操做,若是使用from size的方式,將存在極大的資源浪費(由於from過大),固然若是size過大則問題更爲嚴重,服務器內存會被吃光。所以不少站點的查詢,都不會容許查看過大的page,深度分頁的問題在關係數據庫中一樣存在。大數據

 


 

 

如何正確遍歷索引中的數據

在ES中遍歷索引的推薦方式是採用scroll操做,或者在不須要排序而僅僅須要遍歷的狀況下,能夠採用scroll_scan進一步提高性能。

詳細可見:Scroll的官方說明

 

簡單描述一下Scroll的工做原理:

1:對須要遍歷(或獲取某個知足條件的子集)的索引,規劃一個合理的size做爲分頁大小;

2:在POST的查詢中,增長?scroll=1m(expire time)的query string;

3:在該次查詢中,返回結果中除了查詢結果之外,還有一個scroll_id(很長),這個scroll_id能夠看作是第一次查詢時目標索引的快照的遊標

4:以後直接在GET請求中將scroll_id做爲query string傳遞,或在POST請求中加入scroll_id便可獲取下一批數據,直到沒有數據爲止,如此實現對全部目標數據的遍歷。

(注:在使用scroll遍歷的過程當中,不須要再指定各類查詢條件好比索引名,size大小什麼的,只須要指定scroll_id便可,還能夠指定scroll:1m之類的過時時間,相同條件下有效期內的scroll操做,返回的scroll_id是不會變的,僅僅是scroll_id這個遊標向前走,返回下一批數據而已)

 

scroll_id能夠被顯式刪除,若是你須要重置對查詢目標的遍歷過程的話。

 

若是遍歷過程不須要對數據進行排序,可使用更爲高效的scroll_scan方式進行,以下:

POST ip:port/my_index/my_type/_search?search_type=scan&scroll=1m&size=50
{
    "query": { "match_all": {}}
}

這裏須要注意的是,search_type指定爲scan,即無需排序,而size=50是指每一個shard上的size是50,最終返回數據是shard*size。

初次之外,scroll_scan與普通的scroll還有以下三點不一樣:

  1. Scroll-Scan 結果沒有排序,按 index 順序返回,沒有排序,能夠提升取數據性能。
  2. 初始化時只返回 _scroll_id,沒有具體的 hits 結果
  3. size 控制的是每一個分片的返回的數據量而不是整個請求返回的數據量

 

關於scroll操做是否線程安全的問題,es的客戶端(java&c#)均爲線程安全,所以我認爲經過客戶端來進行的scroll請求也是線程安全的。若是有錯誤請指出。

 

 

 

2016-09-14補充:

 

利用scroll_id獲取數據的同時,ES將返回當前查詢的scroll_id,在其失效或被刪除以前,這個scroll_id都不變,若是但願程序的可靠性更高,能夠用每次返回的scroll_id更新查詢POST所發送的scroll_id;同時,對經過scroll_id查詢返回的結果集進行判空,以肯定當前scroll_id是否已失效,從而須要從新獲取scroll_id。

相關文章
相關標籤/搜索