Elastic Stack-Elasticsearch使用介紹(四)


一、前言

    上一篇說了一下查詢和存儲機制,接下來我們主要來說一下排序、聚合、分頁;

    寫完文章以后發現之前文章沒有介紹Coordinating Node,這個地方補充說明下Coordinating Node(協調節點):搜索請求或索引請求可能涉及保存在不同數據節點上的數據。例如,搜索請求在兩個階段中執行,當客戶端請求到節點上這個階段的時候,協調節點將請求轉發到保存數據的數據節點。每個數據節點在分片執行請求並將其結果返回給協調節點。當節點返回到客端這個階段的時候,協調節點將每個數據節點的結果減少為單個節點的所有數據的結果集。這意味着每個節點具有全部三個node.master,node.data並node.ingest這個屬性,當node.ingest設置為false僅作為協調節點,不能被禁用。

二、排序

   ES默認使用相關性算分來排序,如果想改變排序規則可以使用sort:

   

  也可以指定多個排序條件:

   

   排序的過程是指是對字段原始內容排序的過程,在排序的過程中使用的正排索引,是通過文檔的id和字段進行排序的;Elasticsearch針對這種情況提供兩種實現方式:fielddata和doc_value;

   fielddata

   fielddata的數據結構,其實根據倒排索引反向出來的一個正排索引,即document到term的映射。只要我們針對需要分詞的字段設置了fielddata,就可以使用該字段進行聚合,排序等。我們設置為true之后,在索引期間,就會以列式存儲在內存中。為什么存在於內存呢,因為按照term聚合,需要執行更加復雜的算法和操作,如果基於磁盤或者 OS 緩存,性能會比較差。用法如下:

   

   fielddata加載到內存中有幾種情況,默認是懶加載。即對一個分詞的字段執行聚合或者排序的時候,加載到內存。所以他不是在索引創建期間創建的,而是查詢在期間創建的。

   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種類型的分頁,如下圖:

   

   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值進行查詢

 

  通過保證排序字段唯一,我們實現類似數據庫游標功能的效果; 

四、聚合分析

  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分析使用是近似統計算法,就是結果近似准確但是不一定精確,可以通過參數的調整使其結果精確,意味着會有更多的時間和更大的性能消耗。

五、結束語

Search分析到此基本結束,下一篇介紹一些常用的優化手段和建立索引時的考慮問題;歡迎大家加群438836709,歡迎大家關注我公眾號!


免責聲明!

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



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