正確遍歷ElasticSearch索引


1:ElasticSearch的查詢過程

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

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


 

ElasticSearch的查詢過程

es的數據查詢分兩步:

第一步是的結果是獲取滿足查詢條件的,分布於各個shard上的_doc_id及對應_score;

第二步是根據第一步獲取的所有的_doc_id,去各個shard上獲取數據明細,合並返回客戶端。

 

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

 


 

 

由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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM