ES 文檔與索引介紹
- 2022 年 4 月 15 日
- 筆記
- elasticsearch
在之前的文章中,介紹了 ES 整體的架構和內容,這篇主要針對 ES 最小的存儲單位 – 文檔以及由文檔組成的索引進行詳細介紹。
會涉及到如下的內容:
- 文檔的 CURD 操作。
- Dynamic Mapping 和顯示 Mapping 的區別
- 常見 Mapping 類型與常見參數介紹
- Index Template 和 Dynamic Template
對文檔進行操作
單個文檔 CRUD
和常見的資料庫類似,ES 也支援 CURD 操作:
下面展示了對單個 ES 文檔的操作:
操作名稱 | URL | 解釋 |
---|---|---|
Index | ![]() |
創建或者更新索引中的文檔。在指定 id 的情況下,如果 id 存在,則會更新。如果不指定,則會創建。 |
Get | ![]() |
查詢某個文檔。 |
Delete | DELETE / |
刪除某個指定的文檔。 |
Update | POST / |
更新某個文檔中的內容,可以理解成 Patch 的更新。如果想完全替換文檔,請使用 index. |
下面是實際操作文檔的例子, 打開 kibana 的開發者工具:
先來創建一個文檔:
ES 在創建文檔時,會有兩種方式 index 和 create。index 與 create 不同在於,在指定 id 的情況下,如果 id 存在,index 會覆蓋,同時版本號+1,而 create 會報錯不讓創建。
這裡手動指定 id 為10,使用 index 方法,創建了一個文檔,注意版本號為 1。
注意再次發送同樣的情況,可以看到正常執行,版本號變成 2了。
但是使用 create 方法:
這裡報錯,顯示文檔已經存在。
需要注意的 ES 這裡的更新並不是正常理解的更新,而是先把老文檔刪掉,然後創建一個新文檔出來。
接著對文檔進行更新:
可以看到這裡只更新 user 欄位,這種更新和之前 index 那種更新不同,屬於部分更新,將增加的內容 merge 進原始文檔。
對文檔進行讀取,這裡由於之前更新了三次,所以 version = 3:
刪除文檔就很好理解了,但有一點需要注意,刪除文檔時並不會立馬釋放空間,而是將文檔標記位 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 欄位。
當 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 開頭時,就會使用該索引。
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 手動規定創建的類型。
參考
//www.elastic.co/guide/en/elasticsearch/reference/7.16/docs.html
//www.elastic.co/guide/en/elasticsearch/reference/7.1/mapping-params.html
//www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-templates.html