Elasticsearch 中映射參數doc_values 和 fielddata分析比較


doc_values
默認情況下,大部分字段是索引的,這樣讓這些字段可被搜索。倒排索引(inverted index)允許查詢請求在詞項列表中查找搜索項(search term),並立即獲得包含該詞項的文檔列表。
 
倒排索引(inverted index):
如果我們想要獲得所有包含 brown 的文檔的詞的完整列表,我們會創建如下查詢:
GET /my_index/_search
{
  "query" : {
    "match" : {
      "body" : "brown"
    }
  },
  "aggs" : {
    "popular_terms": {
      "terms" : {
        "field" : "body"
      }
    }
  }
}
 
倒排索引是根據詞項來排序的,所以我們首先在詞項列表中找到 brown,然后掃描所有列,找到包含 brown 的文檔。我們可以快速看到 Doc_1 和 Doc_2 包含 brown 這個 token。
然后,對於聚合部分,我們需要找到 Doc_1 和 Doc_2 里所有唯一的詞項。用倒排索引做這件事情代價很高: 我們會迭代索引里的每個詞項並收集 Doc_1 和 Doc_2 列里面 token。這很慢而且難以擴展:隨着詞項和文檔的數量增加,執行時間也會增加。
Doc values 通過轉置兩者間的關系來解決這個問題。倒排索引將詞項映射到包含它們的文檔,doc values 將文檔映射到它們包含的詞項:
當數據被轉置之后,想要收集到 Doc_1 和 Doc_2 的唯一 token 會非常容易。獲得每個文檔行,獲取所有的詞項,然后求兩個集合的並集。
 
Doc values 可以使聚合更快、更高效並且內存友好。Doc values 的存在是因為倒排索引只對某些操作是高效的。
倒排索引的優勢:在於查找包含某個項的文檔,而對於從另外一個方向的相反操作並不高效,即:確定哪些項是否存在單個文檔里,聚合需要這種訪問模式。
 
在 Elasticsearch 中,Doc Values 就是一種列式存儲結構,默認情況下每個字段的 Doc Values 都是激活的,Doc Values 是在索引時創建的。當字段索引時,Elasticsearch 為了能夠快速檢索,會把字段的值加入倒排索引中,同時它也會存儲該字段的 `Doc Values`。
 
Elasticsearch 中的 Doc Values 常被應用到以下場景:
  • 對一個字段進行排序
  • 對一個字段進行聚合
  • 某些過濾,比如地理位置過濾
  • 某些與字段相關的腳本計算
 
因為文檔值(doc values)被序列化到磁盤,我們可以依靠操作系統的幫助來快速訪問。當 working set 遠小於節點的可用內存,系統會自動將所有的文檔值保存在內存中,使得其讀寫十分高速;當其遠大於可用內存,操作系統會自動把 Doc Values 加載到系統的頁緩存中,從而避免了 jvm 堆內存溢出異常。
 
因此,搜索和聚合是相互緊密纏繞的。搜索使用倒排索引查找文檔,聚合操作收集和聚合 doc values 里的數據。
 
doc values 支持大部分字段類型,但是text 字段類型不支持(因為analyzed)。
(1) status_code 字段默認啟動 doc_values 屬性;
(2) session_id 顯式設置 doc_values = false,但是仍然可以被查詢;
 
如果確信某字段不需要排序或者聚合,或者從腳本中訪問字段值,那么我們可以設置 doc_values = false,這樣可以節省磁盤空間。
 
fielddata
與 doc values 不同,fielddata 構建和管理 100% 在內存中,常駐於 JVM 內存堆。這意味着它本質上是不可擴展的。
 
fielddata可能會消耗大量的堆空間,尤其是在加載高基數(high cardinality)text字段時。一旦fielddata已加載到堆中,它將在該段的生命周期內保留。此外,加載fielddata是一個昂貴的過程,可能會導致用戶遇到延遲命中。這就是默認情況下禁用fielddata的原因。
 
如果需要對 text 類型字段進行排序、聚合、或者從腳本中訪問字段值,則會出現如下異常:
Fielddata is disabled on text fields by default. Set fielddata=true on [your_field_name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.
 
但是,在啟動fielddata 設置之前,需要考慮為什么針對text 類型字段進行排序、聚合、或腳本呢?通常情況下,這是不太合理的。
text字段在索引時,例如New York,這樣的詞會被分詞,會被拆成new、york 2個詞項,這樣當搜索new 或 york時,可以被搜索到。在此字段上面來一個terms的聚合會返回一個new的bucket和一個york的bucket,但是你可能想要的是一個單一new york的bucket。
 
怎么解決這一問題呢?
你可以使用 text 字段來實現全文本查詢,同時使用一個未分詞的 keyword 字段,且啟用doc_values,來處理聚合操作。
(1) 使用my_field 字段用於查詢;
(2) 使用my_field.keyword 字段用於聚合、排序、或腳本;
 
可以使用 PUT mapping API 在現有text 字段上啟用 fielddata,如下所示:
 
 《Elasticsearch 7.x從入門到精通》專欄會通過理論與實踐相結合的方式,帶領你一步一步走進Elasticsearch的世界,使你輕松掌握Elasticsearch的基本概念,學習Elasticsearch的服務搭建,了解Elasticsearch的常用技巧,並通過案例項目讓你擁有實際的應用能力。 同時,也會講解Elastic Stack中其他相關組件,如Logstash、Beats和Kibana等等。


免責聲明!

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



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