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還有以下三點不一樣:
關於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。