在之前的文章中,介紹了 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 手動規定建立的型別。
參考
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