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等等。
相關文章
相關標籤/搜索