天天看點

Elasticsearch-6.x 反向索引,doc_values,Fielddata, store研究一.反向索引二.doc_values 文檔值三.Fielddata 四.store存儲

一.反向索引

反向索引的概念,感興趣的可以點選檢視<<ES權威指南中關于反向索引的解釋>>

也可以檢視elasticsearch簡介和倒排序索引介紹這篇文章,寫的很清晰。

1.1 字段和反向索引的關系

首先,在es中,我們可以把一個doc(文檔)了解為資料庫中的一行資料,每個doc對應多個field(字段),例如:

PUT /employee/group/1
{
    "age" : 25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}
PUT /employee/group/2
{
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}
           

es中,會在_source中将資料存一份,然後,寫入資料的同時,自動生成mapping資訊,根據mapping資訊,生成字段對應的反向索引檔案。

自動生成的mapping如下:

{
  "employee": {
    "mappings": {
      "group": {
        "properties": {
          "about": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "age": {
            "type": "long"
          },
          "interests": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}
           

按照字段,分别生成反向索引檔案,然後檢索字段的時候,搜尋字段對應的反向索引檔案即可,如下:

age字段:

age字段因為是long類型,整個字段無需分詞(term,token),直接按字段值做反向索引。

age-1-反向索引檔案

term詞條 docID
25 1
32 2

about字段本身為text類型,支援分詞,about.keyword多域字段為keyword類型,按整詞作為term詞條,是以産生about,about.keyword兩個字段的反向索引檔案。

about-1 反向索引檔案

term詞條 docID
i 1,2
love 1
to 1,2
go 1
rock 1,2
climbing 1
like 2
collect  2
albums 2

about.keyword-1反向索引檔案

term詞條 docID
I love to go rock climbing 1
I like to collect rock albums 2

ES檢索過程:

1.根據檢索字段,如果是text類型的,按照寫入索引時的分詞機制,進行查詢關鍵字分詞,

2.查詢字段對應的反向索引檔案,查詢term分詞,得到對應的docID

3.根據docID,獲得doc,顯示查詢結果。

提問:

1.about.keyword的作用,換而言之,keyword資料類型和text資料類型的差別?

"about":"I love to go rock climbing"
           

對上面的about字段,keyword資料類型隻支援精确搜尋,因為keyword建立的索引檔案的term,是全詞建立索引,沒有分詞,是以,對于檢索 about:"i",如果格式為keyword将傳回null,無搜尋結果。如果格式為text,則分詞後建立索引,搜尋  about:"i",有結果,因為有I 的term,由此可見,分詞機制對搜尋影響很大,因為term隻能完全比對,才會得到term對應的文檔。

反向索引的不足

1.反向索引,按分詞建立,建立後不可修改。

ES針對修改反向索引,使用的是再合并政策:對修改的資料建立新的,小的索引檔案,記錄時間,新的索引檔案和舊的索引檔案合并,修改的部分,按時間最新覆寫。

2.反向索引可以很快的通過分詞,得到包含分詞的文檔。但是,如果我們已知文檔,想得到文檔擁有哪些分詞,需要周遊整個反向索引檔案,影響效率。

解決辦法是引入doc_values,doc_values是文檔對應的分詞形成的索引檔案。

3.反向索引十分依賴分詞機制,分詞機制不好,則搜尋結果不理想

ES提供很多分詞機制,也支援自定義分詞機制。當然,如果不需要分詞,隻需要精準比對,直接建立keyword類型資料即可。

二.doc_values 文檔值

2.1. doc_values是什麼

doc_values是elasticsearch中,對于反向索引的部分缺點進行部分補充的功能。檢視dov_values官方解釋

反向索引很友善單項檢視 分詞對應的文檔,但是不利于反向檢視,文檔所有的分詞。doc_values可以了解為反向的反向索引,

doc_values存放的是文檔對應的分詞

2.1 doc_values的應用場景

上面說doc_values 是為了滿足反向查詢反向索引而建立的。那麼,什麼樣的情況我們需要用到doc_values呢。大緻說來,聚合,排序,都會用到doc_values,

首先,我們進行一次聚合。

//增加一條記錄
PUT /employee/group/3
{
    "age" :         32,
    "about" :       "I like to read book",
    "interests":  [ "music","books" ]
}
//查詢abount中有i的,按age聚合,統計文檔數
GET /employee/_search
{
  "query" : {
    "match" : {
      "about" : "i"
    }
  },
  "aggs" : {
    "res": {
      "terms" : {
        "field" : "age"
      }
    }
  }
}
           

這條語句主要是為了分析,每個資料出現的次數,例如,music有多少人喜歡,sports有多少人喜歡。結果如下:

{
  "aggregations": {
    "res": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 32,                   //age=32的有兩個文檔
          "doc_count": 2
        },
        {
          "key": 25,                   //age=25的有一個文檔
          "doc_count": 1
        }
      ]
    }
  }
}
           

将上面的查詢聚合過程分解:

1.執行query,查詢about中包含i這個term的doc。得到文檔1,2,3

2.得到文檔1,2,3後,我們分析1,2,3的age字段,判斷每個age的有多少人。

在第2步中,如果我們隻有反向索引檔案,我們需要周遊整個反向索引,去擷取,1,2,3文檔的age索引檔案,按照age索引檔案的term(age是數值類型,整詞形成反向索引,不進行分詞),即age的值,然後合并統計文檔數。

但是如果我們有doc_values之後,就很友善統計了。

doc_values是和反向索引同時建立的。同樣按索引/類型/字段區分索引檔案,doc_value生成資料為:

age-1-doc_values索引檔案

文檔ID 包含的term(不分詞的term,即字段對應的值)
1 25
2 32
3 32

有了doc_values的查詢聚合過程如下:

1.執行query,查詢about中包含i這個term的doc。得到文檔1,2,3

2.得到文檔1,2,3後,查詢age對應的doc_values索引檔案,将age合并,計數,得到25->1,32->2,傳回結果。

搜尋和聚合是互相緊密纏繞的。搜尋使用反向索引查找文檔,聚合操作收集和聚合 doc values 裡的資料。

注意:

doc_values對不分詞的字段預設開啟,包括about.keyword這類多域字段,對分詞字段預設關閉,即about字段

#分詞字段# 從資料類型來看,text預設進行分詞,keyword,long,int,double,複雜資料類型等預設不進行分詞

剛才的描述中,經常強調doc_values存放的是 文檔對應的分詞數,這句話是容易引起歧義的,但是又是正确的,如果,該字段不允許分詞,則該字段的值,就是該文檔在這個索引檔案的唯一分詞(即term),對于能分詞的字段,doc_values是預設關閉,但是可以手動開啟,這個時候,doc_values存放的是文檔對應的分詞數 ,這句話就是正确的。

是以,對于doc_values的用途,ES官網的說法是:

Doc values 不僅可以用于聚合。 任何需要查找某個文檔包含的值的操作都必須使用它。 除了聚合,還包括排序,通路字段值的腳本,父子關系處理,參見 父-子關系文檔 

#為什麼對分詞字段關閉#  沒找到官方解釋 、個人看法:對分詞字段,開啟doc_values,産生的索引檔案占用磁盤過大,處理的時候,消耗cpu資源,

doc_values的優缺點

1.doc_values 提高了聚合,排序,所有針對字段值的操作的效率,

2.doc_values加大了磁盤空間,但是ES提供了doc_values的壓縮算法,對doc_values進行了大量壓縮。而且,用不到可以禁用,節省空間。

三.Fielddata 

3.1 fielddata是什麼

因為doc_values不針對分詞字段,那麼,如果一定要對分詞字段的term分詞進行聚合,該怎麼辦呢?

在es中,對分詞的field,直接執行聚合操作,會報錯,

{
        "type": "illegal_argument_exception",
        "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [about] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
      }
           

大概意思是說,你必須要打開fielddata,然後将正排索引資料加載到記憶體中,才可以對分詞的field執行聚合操作,而且會消耗很大的記憶體

fielddata就是滿足該需求的,但是,因為過于消耗資源,是以預設關閉。

fielddata結構和doc_values相同,差別是.fielddata運算時在記憶體中生成,純記憶體計算,doc_values放在磁盤中即可

有需求時,在mapping中打開fielddata開關。預設false關閉。

doc_values和fielddata詳細說明可以檢視部落格 elasticsearch的Doc Values 和 Fielddata

四.store存儲

字段獨立于_source,單獨存儲,

注:_source中依然會存儲該字段

優點: ES中,所有資料統一存在_source中,如果隻是查詢一個小字段,卻要把_source中的整條資料顯示後,再從_source中取出對應的字段,浪費資源。

缺點: 加大磁盤使用。

應用場景: 如果_source很大,頻繁使用的字段很小,則應該store該字段,這樣不需要每次都将_source加載完後,在查找該字段。

繼續閱讀