1、前言html
上一篇說了一下查詢和存儲機制,接下來咱們主要來講一下排序、聚合、分頁;node
寫完文章之後發現以前文章沒有介紹Coordinating Node,這個地方補充說明下Coordinating Node(協調節點):搜索請求或索引請求可能涉及保存在不一樣數據節點上的數據。例如,搜索請求在兩個階段中執行,當客戶端請求到節點上這個階段的時候,協調節點將請求轉發到保存數據的數據節點。每一個數據節點在分片執行請求並將其結果返回給協調節點。當節點返回到客端這個階段的時候,協調節點將每一個數據節點的結果減小爲單個節點的全部數據的結果集。這意味着每一個節點具備所有三個node.master,node.data並node.ingest這個屬性,當node.ingest設置爲false僅做爲協調節點,不能被禁用。算法
2、排序數據庫
ES默認使用相關性算分來排序,若是想改變排序規則可使用sort:api
也能夠指定多個排序條件:數組
排序的過程是指是對字段原始內容排序的過程,在排序的過程當中使用的正排索引,是經過文檔的id和字段進行排序的;Elasticsearch針對這種狀況提供兩種實現方式:fielddata和doc_value;緩存
fielddata數據結構
fielddata的數據結構,其實根據倒排索引反向出來的一個正排索引,即document到term的映射。只要咱們針對須要分詞的字段設置了fielddata,就可使用該字段進行聚合,排序等。咱們設置爲true以後,在索引期間,就會以列式存儲在內存中。爲何存在於內存呢,由於按照term聚合,須要執行更加複雜的算法和操做,若是基於磁盤或者 OS 緩存,性能會比較差。用法以下:elasticsearch
fielddata加載到內存中有幾種狀況,默認是懶加載。即對一個分詞的字段執行聚合或者排序的時候,加載到內存。因此他不是在索引建立期間建立的,而是查詢在期間建立的。ide
fielddata在內存中加載的這樣就會出現一個問題,數據量很大的狀況容易發生OOM,這種時候咱們該如何控制OOM的狀況發生?
1.內存限制
indices.fielddata.cache.size: 20% 默認是無限制,限制內存使用之後頻繁的致使內存回收,容易照成GC和IO損耗。
2.斷路器(circuit breaker)
若是查詢一次的fielddata超過總內存,就會發生內存溢出,circuit breaker會估算query要加載的fielddata大小,若是超出總內存,就短路,query直接失敗;
indices.breaker.fielddata.limit:fielddata的內存限制,默認60%
indices.breaker.request.limit:執行聚合的內存限制,默認40%
indices.breaker.total.limit:綜合上面兩個,限制在70%之內
3.頻率(frequency)
加載fielddata的時候,也是按照segment去進行加載的,因此能夠經過限制segment文檔出現的頻率去限制加載的數目;
min :0.01 只是加載至少1%的doc文檔中出現過的term對應的文檔;
min_segment_size: 500 少於500 文檔數的segment不加載fielddata;
fielddata加載方式:
1.lazy
這個在查詢的放入到內存中,上面已經介紹過;
2.eager(預加載)
當一個新的segment造成的時候,就加載到內存中,查詢的時候遇到這個segment直接查詢出去就能夠;
3.eager_global_ordinals(全局序號加載)
構建一個全局的Hash,新出現的文檔加入Hash,文檔中用序號代替字符,這樣會減小內存的消耗,可是每次要是有segment新增或者刪除時候回致使全局序號重建的問題;
doc_value
fielddata對內存要求比較高,若是數據量很大的話對內存是一個很大的考驗。因此Elasticsearch又給咱們提供了另外的策略doc_value,doc_value使用磁盤存儲,與fielddata結構徹底是同樣的,在倒排索引基礎上反向出來的正排索引,而且是預先構建,即在建倒排索引的時候,就會建立doc values。,這會消耗額外的存儲空間,可是對於JVM的內存需求就會減小。整體來看,dov_valus只是比fielddata慢一點,大概10-25%,則帶來了更多的穩定性。
類型是string的字段,生成分詞字段(text)和不分詞字段(keyword),不分詞字段即便用keyword,因此咱們在聚合的時候,能夠直接使用field.keyword進行聚合,而這種默認就是使用doc_values,創建正排索引。不分詞的字段,默認創建doc_values,即字段類型爲keyword,他不會建立分詞,就會默認創建doc_value,若是咱們不想該字段參與聚合排序,咱們能夠設置doc_values=false,避免沒必要要的磁盤空間浪費。可是這個只能在索引映射的時候作,即索引映射建好以後不能修改。
二者對比:
3、分頁
有3種類型的分頁,以下圖:
1.from/size
form開始的位置,size獲取的數量;
數據在分片存儲的狀況下怎麼查詢前1000個文檔?
在每一個分片上都先獲取1000個文檔,而後再由Coordinating Node聚合全部分片的結果後再排序選取前1000個文檔,頁數越多,處理文檔就越多,佔用內存越多,耗時越長。數據分別存放在不一樣的分片上,必須一個去查詢;爲了不深度分頁,Elasticsearch經過index.max_result_window限定顯示條數,默認是10000;
2.scroll
scroll按照快照的方式來查詢數據,能夠避免深度分頁的問題,由於是快照因此不能用來作實時搜索,數據不是實時的,接下來講一下scroll流程:
首先發起scroll查詢請求,Elasticsearch在接收到請求之後會根據查詢條件查詢文檔i,1m表示該快照保留1分鐘;
接下來查詢的時候根據上一次返回的快照id繼續查詢,不斷的迭代調用直到返回hits.hits數組爲空時中止
過多的scroll調用會佔用大量的內存,能夠經過刪除的clear api進行刪除:
刪除某個:
刪除多個:
刪除全部:
3.search after
避免深度分頁的性能問題,提供實時的下一頁文檔獲取功能,經過提供實時遊標來解決此問題,接下來咱們來解釋下這個問題:
第一次查詢:這個地方必須保證排序的值是惟一的
第二步: 使用上一步最後一個文檔的sort值進行查詢
經過保證排序字段惟一,咱們實現相似數據庫遊標功能的效果;
4、聚合分析
Aggregation,是Elasticsearch除搜索功能外提供的針對Elasticsearch數據作統計分析的功能,聚合的實時性很高,都是及時返回,另外還提供多種分析方式,接下來咱們看下聚合的4種分析方式:
Metric
在一組文檔中計算平均值、最大值、最小值、求和等等;
Avg(平均值)
Min最小值
Sum求和(過濾查詢中的結果查詢出帽子的價格的總和)
Percentile計算從聚合文檔中提取的數值的一個或多個百分位數;
解釋下下面這個例子,網站響應時間作的一個分析,單位是毫秒,5毫秒響應占總響應時間的1%;
Cardinality計算不一樣值的近似計數,相似數據庫的distinct count
固然除了上面還包括不少類型,更加詳細的內容能夠參考官方文檔;
Bucket
按照必定的規則將文檔分配到不一樣的桶裏,達到分類分析的目的;
好比把年齡小於10放入第一個桶,大於10小於30放入第二個桶裏,大於30放到第三個桶裏;
接下來咱們介紹咱們幾個經常使用的類型:
Date Range
根據時間範圍來劃分桶的規則;
to表示小於當前時間減去10個月;from大於當前時間減去10個月;format設定返回格式;form和to還能夠指定範圍,大於某時間小於某時間;
Range
經過自定義範圍來劃分桶的規則;
這樣就能夠輕易作到上面按照年齡分組統計的規則;
Terms
直接按照term分桶,相似數據庫group by之後求和,若是是text類型則按照分詞結果分桶;
比較經常使用的類型大概就是這3種,好比還有什麼Histogram等等,你們能夠參考官方文檔;
Pipeline
對聚合的結果在次進行聚合分析,根據輸出的結果不一樣能夠分紅2類:
Parent
將返回的結果內嵌到現有的聚合結果中,主要有3種類型:
1.Derivative
計算Bucket值的導數;
2.Moving Average
計算Bucket值的移動平均值,必定時間段,對時間序列數據進行移動計算平均值;
3.Cumulatove Sum
計算累計加和;
Sibling
返回的結果與現有聚合結果同級;
1.Max/Min/Avg/Sum
2.Stats/Extended
Stats用於計算聚合中指定列的全部桶中的各類統計信息;
Extended對Stats的擴展,提供了更多統計數據(平方和,標準誤差等);
3.Percentiles
Percentiles 計算兄弟中指定列的全部桶中的百分位數;
更多介紹,請參考官方文檔;
Matrix
矩陣分析,使用很少,參考官方文檔;
原理探討與數據準確性探討:
Min原理分析:
先從每一個分片計算最小值 -> 再從這些值中計算出最小值
Terms聚合以及提高計算值的準確性:
Terms聚合的執行流程:每一個分片返回top10的數據,Coordinating node拿到數據以後進行整合和排序而後返回給用戶。注意Terms並非永遠準確的,由於數據分散在多個分片上,因此Coordinating node沒法獲得全部數據(這句話有同窗會有疑惑請查看上一篇文章)。若是要解決能夠把分片數設置爲1,消除數據分散的問題,可是會分片數據過多問題,或者設在Shard_Size大小,即每次從Shard上額外多獲取的數據,以提高準確度。
Terms聚合返回結果中有兩個值:
doc_count_error_upper_bound 被遺漏的Term的最大值;
sum_other_doc_count 返回聚合的其餘term的文檔總數;
在Terms中設置show_term_doc_count_error能夠查看每一個聚合誤算的最大值;
Shard_Size默認大小:shard_size = (size*1.5)+10;
經過調整Shard_Size的大小能夠提高準確度,增大了計算量下降響應的時間。
由上面能夠得出在Elasticsearch聚合分析中,Cardinality和Percentile分析使用是近似統計算法,就是結果近似準確可是不必定精確,能夠經過參數的調整使其結果精確,意味着會有更多的時間和更大的性能消耗。
5、結束語
Search分析到此基本結束,下一篇介紹一些經常使用的優化手段和創建索引時的考慮問題;歡迎你們加羣438836709,歡迎你們關注我公衆號!