ES 文檔與索引介紹

在之前的文章中,介紹了 ES 整體的架構和內容,這篇主要針對 ES 最小的存儲單位 - 文檔以及由文檔組成的索引進行詳細介紹。

會涉及到如下的內容:

  1. 文檔的 CURD 操作。
  2. Dynamic Mapping 和顯示 Mapping 的區別
  3. 常見 Mapping 類型與常見參數介紹
  4. Index Template 和 Dynamic Template

對文檔進行操作

單個文檔 CRUD

和常見的數據庫類似,ES 也支持 CURD 操作:

下面展示了對單個 ES 文檔的操作:

操作名稱 URL 解釋
Index image-20220406215957677 創建或者更新索引中的文檔。在指定 id 的情況下,如果 id 存在,則會更新。如果不指定,則會創建。
Get image-20220406220223805 查詢某個文檔。
Delete DELETE //_doc/<_id> 刪除某個指定的文檔。
Update POST //_update/<_id> 更新某個文檔中的內容,可以理解成 Patch 的更新。如果想完全替換文檔,請使用 index.

下面是實際操作文檔的例子, 打開 kibana 的開發者工具:

先來創建一個文檔:

ES 在創建文檔時,會有兩種方式 index 和 create。index 與 create 不同在於,在指定 id 的情況下,如果 id 存在,index 會覆蓋,同時版本號+1,而 create 會報錯不讓創建。

這裏手動指定 id 爲10,使用 index 方法,創建了一個文檔,注意版本號爲 1。

image-20220406222248162

注意再次發送同樣的情況,可以看到正常執行,版本號變成 2了。

image-20220406222310526

但是使用 create 方法:

image-20220406222351472

這裏報錯,顯示文檔已經存在。

需要注意的 ES 這裏的更新並不是正常理解的更新,而是先把老文檔刪掉,然後創建一個新文檔出來。

接着對文檔進行更新:

image-20220407073426264

可以看到這裏只更新 user 字段,這種更新和之前 index 那種更新不同,屬於部分更新,將增加的內容 merge 進原始文檔。

對文檔進行讀取,這裏由於之前更新了三次,所以 version = 3:

image-20220407073714504

刪除文檔就很好理解了,但有一點需要注意,刪除文檔時並不會立馬釋放空間,而是將文檔標記位 deleted 狀態,後臺進程會在合適的時候清理這些標記位已經刪除的文檔。

批量文檔操作

批量寫入

相較於當個文檔的操作,大批量的操作對於 ES 來說,是更爲常見的場景。ES 也提供了批量 API,該 API 支持在一次 API請求中包含 4 種類型, 並且 Response 中會針對每一條操作返回一個對應的結果。

POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

批量讀取

可以同時傳入多個文檔 id,進行讀取,多個文檔可以屬於不同的索引。

GET /_mget
{
  "docs": [
    {
      "_index": "my-index-000001",
      "_id": "1"
    },
    {
      "_index": "my-index-000001",
      "_id": "2"
    }
  ]
}

索引 - Mapping

索引是多個文檔的集合,體現了邏輯空間的概念。對於每個索引來說都可以設置 Mapping 和 Setting 兩部分。

其中 Mapping 定義了文檔包含字段的類型與名稱,以及如倒排索引,分詞的一些設置。Setting 定義瞭如何將數據分佈保存在不同的節點上。

數據類型

ES 中的數據類型分爲三種:

  • 簡單類型
  • 複雜類型
    • 對象類型
    • 嵌套類型
  • 特殊類型
    • 地理位置等

下圖中顯示了 ES 中常見的簡單數據類型以及和 SQL 對應的關係。

Elasticsearch type Elasticsearch SQL type SQL type SQL precision
Core types
null null NULL 0
boolean boolean BOOLEAN 1
byte byte TINYINT 3
short short SMALLINT 5
integer integer INTEGER 10
long long BIGINT 19
double double DOUBLE 15
float float REAL 7
half_float half_float FLOAT 3
scaled_float scaled_float DOUBLE 15
keyword type family keyword VARCHAR 32,766
text text VARCHAR 2,147,483,647
binary binary VARBINARY 2,147,483,647
date datetime TIMESTAMP 29
ip ip VARCHAR 39

Dynamic Mapping

我們知道,Mapping 類似於數據庫 Scheme 的定義,但回想之前對文檔 CURD 的操作時,我們並未手動設置 Mapping,但可以自動創建文檔,原因就在於利用了 Dynamic Mapping 的特性。就是即使索引不存在時,也可以手動創建索引,並根據文檔信息自動推算出對應的 Mapping 關係。

比如之前創建的文檔,如下就是生成的 Mapping 關係,ES 自動將 company 和 user 推斷爲 text 字段。

image-20220407085317352

當 Dynamic Mapping 也有自己的缺點:就是推算不準確,比如上面的例子,company 和 user 的字段爲 keyword 類型更爲合適,以至於搜索時出現一些問題。

dynamic Mapping 可以通過 dynamic 字段進行控制, 其值爲 true,false,strict 三種類型。

對於已經創建的索引,在修改 Mapping 分爲兩種情況:

  • 增加新的字段:
    • dynamic 爲 true,新字段寫入後,Mapping 也會被更新
    • dynamic 爲 false,字段可以寫入到 _source, 但 Mapping 不會被更新,自然也不會被索引
    • dynamic 爲 strict,不允許寫入
  • 修改已經存在字段的類型:
    • 不允許修改,因爲 Lucene 生成的倒排索引,不允許被修改。
    • 除非重新生成索引。

顯示指定 Mapping

與 Dynamic Mapping 不同,顯示指定 Mapping 可以允許我們手動指定 Mapping 結構。

編寫 Mapping 有兩種方式:

  • 可以參考 doc
  • 利用 dynamic 自動創建功能,查詢後,自己再編輯成想要的結構。

看一個簡單的例子:

PUT user
 {
  "user" : {
    "mappings" : {
      "properties" : {
        "company" : {
          "type" : "keyword"
          "null_value": "NULL"
          }
        },
        "name" : {
          "type" : "keyword",
          "index_options": "offsets"
        },
        "id_card" : {
          "type" : "keyword",
          "index": false # 表示該字段不需要被索引,不用被搜索到
        }
      }
  }
}

"null_value":表示對 NULL 值可以進行搜索。

"index": false 表示該字段不需要被索引,不用被搜索到

"index_options": "offsets" 表示對倒排索引的結構進行設置:

  • docs :表示記錄 doc id
  • freqs :表示記錄 doc id 和 term frequencies
  • position :表示記錄 doc id 和 term frequencies 和 term position(Text 類型默認記錄爲 position)
  • offsets: 表示記錄 doc id 和 term frequencies 和 term position 以及 character offset.

關於倒排可以查看之前寫的這篇文章

Index Template 和 Dynamic Template

Index Template

考慮到數據不斷增長的情況的,就需要按照一定的規則,將數據分散在不同的 Index 中。但每次都需要爲每個 Index 設置 Mapping 和 Setting 關係。

這時 Index Template 就可以很好滿足這個需求。

在 Index Template 中,可以通過設置一個通配名稱,當創建的索引的名稱,滿足該條件時,就會使用模板的規則。

Note:

  • 模板只會在創建新索引時生效,修改模板不會影響已經創建的索引。
  • 可以設置多個模板,通過 "order" 參數,控制那個模板的規則生效。

下面這個例子就是爲告警建立的一個 template,當創建的名字以 alarm 開頭時,就會使用該索引。

image-20220415092031928

Dynamic Template

在上面 Dynamic Mapping 的介紹中知道,ES 對於沒有設置 Mapping 字段的內容,會自己推算一個類型,但這就可能造成推算類型不準確的情況。

這時就可以用 Dynamic Template 來解決,通過規範插入的字段的名稱,來指定他的類型:

  • 比如可以 is 開頭的字段,都設置成 boolean
  • long_ 開頭的字段,設置成 long
  • 所有字符串類型,設置成 keyword

Dynamic Template 直接作用在索引上, 看下面這個例子。

PUT my-index-000001
{
  "mappings": {
    "dynamic_templates": [
      {
        "longs_as_strings": {
          "match_mapping_type": "string",
          "match":   "long_*",
          "unmatch": "*_text",
          "mapping": {
            "type": "long"
          }
        }
      }
    ]
  }
}

PUT my-index-000001/_doc/1
{
  "long_num": "5", 
  "long_text": "foo" 
}

當匹配到以 long 開頭的字符串時並且不包含以 _text 結尾,會將其設置成 long 類。

總結

本篇文章中,主要是對 ES 文檔和索引的設置進行了說明。

ES 文檔支持 CURD 操作,但需要知道 Index 和 create 的區別在於,對於指定 id 情況下的處理方式不同。同時爲了適應大數據量的讀取和寫入,可以用 bulk api.

對於 ES 索引來說,在創建時,支持兩種方式來指定 Setting 和 Mapping 的關係。一種 Dynamic Mapping,這種方式不需要手動設置 Index 格式,會根據文檔自動的創建,但缺點在於推斷的類型不不準確。而顯示 Mapping,可以手動規定 index 的格式。

考慮到數據不斷增長的情況,需要將數據拆分到不同的 index 上,可以通過 IndexTemplate 實現。

對於 Dynamic Mapping,推斷不準確的情況,可以通過 Dynamic Template 手動規定創建的類型。

參考

https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docs.html

https://www.elastic.co/guide/en/elasticsearch/reference/7.1/mapping-params.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-templates.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章