前面咱們聊了 Elasticsearch 的索引、搜索和分詞器,今天再來聊另外一個基礎內容—— Mapping。html
Mapping 在 Elasticsearch 中的地位至關於關係型數據庫中的 schema,它能夠用來定義索引中字段的名字、定義字段的數據類型,還能夠用來作一些字段的配置。從 Elasticsearch 7.0開始,Mapping 中不在意須要定義 type 信息了,具體緣由能夠看官方的解釋。數據庫
咱們剛剛提到 Mapping 中能夠定義字段的數據類型,這多是 Mapping 最經常使用的功能了,因此咱們先來看看 Elasticsearch 都支持哪些數據類型。數組
Elasticsearch 支持的數據類型遠不止這些,因爲篇幅緣由,這裏就不一一列舉了。我找幾個工做中常見的來介紹一下。bash
首先就是字符串了,Elasticsearch 中的字符串有 text 和 keyword 兩種。其中 text 類型的字符串是能夠被全文檢索的,它會被分詞器做用,session
PUT my_index { "mappings": { "properties": { "full_name": { "type": "text" } } } }
在設置字段類型爲 text 時,還能夠利用一些參數對這個字段進行更進一步的定製。app
index
:標記這個字段是否能被搜索,默認是 trueelasticsearch
search_analyzer
:被搜索時所使用的分詞器,默認使用 setting 中設置的分詞器ide
fielddata
:字段是否容許在內存中進行排序、聚合,默認是 falseui
meta
:關於字段的一些元數據code
像一些id、郵箱、域名這樣的字段,咱們就須要使用 keyword 類型了。由於 keyword 類型能夠支持排序、聚合,而且只能支持精確查詢。
有些同窗可能會把 ID 設置爲數字類型,這也是沒問題的,數字類型和 keyword 各有各的好處,使用數字類型能夠進行範圍查找,而使用 keyword 類型則有更高的查詢效率。具體用哪一種還要看使用場景。
日期類型在 Elasticsearch 中有三種表現形式
"2020-07-26"
和"2015/01/01 12:10:30"
這樣的在 Elasticsearch 內部,日期類型是以 long 類型的毫秒級時間戳存儲的,時區使用的是0時區。
咱們能夠自定義時間格式,默認使用的是strict_date_optional_time||epoch_millis
strict_date_optional_time_nanos是通用的日期格式解析,至少要包含年份,若是要包含時間,則用T
分隔,例如yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ
或 yyyy-MM-dd
。
若是想要同時支持多種日期格式,可使用format
字段
PUT my_index { "mappings": { "properties": { "date": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } }
剛纔咱們提到配置 Mapping 的日期格式的參數format
,Mapping 還提供了不少其餘的參數。
咱們來介紹幾個經常使用的字段。
首先是fields
,它可使同一個字段經過不一樣的方式實現不一樣的目的。
例如,咱們能夠對一個字符串字段設置爲text
類型,用於全文檢索,同時能夠利用fields
設置爲keyword
類型,用於排序和聚合。
PUT my-index-000001 { "mappings": { "properties": { "city": { "type": "text", "fields": { "raw": { "type": "keyword" } } } } } }
查詢時咱們就可使用city
進行全文檢索,使用city.raw
進行排序和聚合。
GET my-index-000001/_search { "query": { "match": { "city": "york" } }, "sort": { "city.raw": "asc" }, "aggs": { "Cities": { "terms": { "field": "city.raw" } } } }
有些時候,咱們只想把某個字段做爲數據存儲來使用,並不須要用來作搜索,這時,咱們就能夠將這個字段禁用掉,字段被禁用之後,它所保存的值也不受 mapping 指定的類型控制。
PUT my-index-000001 { "mappings": { "properties": { "user_id": { "type": "keyword" }, "last_updated": { "type": "date" }, "session_data": { "type": "object", "enabled": false } } } }
上面的例子中,咱們禁用掉了 session_data
這個字段,這時,你既能夠往 session_data
字段中存儲 JSON 格式的數據,也能夠存儲非 JSON 格式的數據。
除了針對於單個字段的禁用之外,咱們還能夠直接禁用掉整個 mapping。咱們來從新建立一個index
PUT my-index-000002 { "mappings": { "enabled": false } }
這時,文檔全部的字段都不會被索引,只是用來存儲。
須要注意的是,不管是具體字段中仍是整個 mapping 的 enabled 屬性都不能夠被修改,由於一旦設置爲 false,Elasticsearch 就不會對字段進行索引了,也不會校驗數據的合法性,若是產生了髒數據之後再設置爲 true,就會形成程序錯誤。
null 在 Elasticsearch 中是不能夠被索引或搜索的,這裏咱們所說的 null 並非狹義上某種語言的 null,而是全部的空值。例如全部值都是 null 的數組,總之,這裏的定義就是沒有值。
對於有須要搜索空值的業務怎麼辦呢?Elasticsearch 爲咱們提供了 null_value
這個參數,它能夠指定一個值,搜索時使用這個值來替代空值。
舉個栗子
PUT my-index-000001 { "mappings": { "properties": { "status_code": { "type": "keyword", "null_value": "NULL" } } } }
咱們給 status_code
字段設置了 null_value
爲 "NULL"
。這裏須要注意, null_value
的類型必須與要查找的數據類型相同,若是在這個例子中 status_code
的類型是long,那麼就不能把null_value
設置爲 "NULL"
。
對於新增長的字段:
_source
中對於已有的字段,一旦已經有數據寫入,就再也不支持修改字段定義
咱們在建立索引時,能夠不用手動寫 Mappings, Elasticsearch 會幫咱們自動識別出字段的類型。咱們稱之爲 Dynamic Mapping。不過有時推算的可能不是很準確。
Elasticsearch 自動識別類型是基於 JSON 的。數據類型的對應關係以下(表格來自 elastic 官網)
JSON data type | Elasticsearch data type |
---|---|
null |
No field is added. |
true or false |
boolean field |
floating point number | float field |
integer | long field |
object | object field |
array | Depends on the first non-null value in the array. |
string | Either a date field (if the value passes date detection), a double or long field (if the value passes numeric detection) or a text field, with a keyword sub-field. |
Elasticsearch 支持的字段映射的數據類型在這個文檔中,除了這些,其餘的類型映射都須要顯示的指定了。
關於日期類型,默認是能夠映射的,可是 Elasticsearch 只能識別幾種格式的日期yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis
。若是關掉了 date_detection
開關,那麼就只能識別爲字符串了。
PUT my-index-000001 { "mappings": { "date_detection": false } }
固然,你也能夠根據須要本身指定要識別的日期格式,只須要使用 dynamic_date_formats
參數便可。
PUT my-index-000001 { "mappings": { "dynamic_date_formats": ["MM/dd/yyyy"] } }
Elasticsearch 還提供了一種把字符串型的數字識別爲數字的能力,它是由 numeric_detection
開關控制的。
PUT my-index-000005 { "mappings": { "numeric_detection": true } } PUT my-index-000005/_doc/1 { "my_float": "1.0", "my_integer": "1" }
在這個例子中,my_float
會被識別爲 float 類型,而 my_integer
會被識別爲 long 類型。
dynamic template 容許咱們自定義 mapping ,並應用到具體索引上。dynamic template 的定義通常是這樣的
"dynamic_templates": [ { "my_template_name": { ... match conditions ... "mapping": { ... } } }, ... ]
my_template_name
能夠是任意字符串。
match conditions
包括match_mapping_type
, match
, match_pattern
, unmatch
, path_match
, path_unmatch
這幾種。
mapping
就是指匹配到的字段應該使用怎樣的 mapping。下面咱們介紹幾種 match conditions
咱們先來看一個簡單的例子
PUT my-index-000001 { "mappings": { "dynamic_templates": [ { "integers": { "match_mapping_type": "long", "mapping": { "type": "integer" } } }, { "strings": { "match_mapping_type": "string", "mapping": { "type": "text", "fields": { "raw": { "type": "keyword", "ignore_above": 256 } } } } } ] } }
這裏咱們有兩個模版,其一是使用 integer
類型來代替 long
類型,其二是將字符串類型映射爲 keyword
。
這兩個比較簡單,match 是指匹配到模式的字段, unmatch 是表示不匹配的字段。
PUT my-index-000001 { "mappings": { "dynamic_templates": [ { "longs_as_strings": { "match_mapping_type": "string", "match": "long_*", "unmatch": "*_text", "mapping": { "type": "long" } } } ] } }
在這個例子中,咱們須要的是 long_
開頭的字符串,不須要 _text
結尾的字符串字段。
除了以上三種以外,其餘的就是 match_pattern
用來進行正則匹配,path_match
和 path_unmatch
則是表示字段所在路徑的是否匹配。
另外 dynamic template 還支持兩種變量替換,分別是 {name}
和 {dynamic_type}
。其實 name 就是字段名,dynamic_type 就是檢測出的字段類型。
關於 Elasticsearch 的 mapping 咱們就先聊這些,我認爲 mapping 的配置是一個須要經驗的事情,當你處理的 case 愈來愈多以後,就能比較輕鬆的知道如何更好的配置 mapping 了。此外,mapping 的許多字段和參數文中都沒有涉及,對於我而言,大部分都是用到了現查文檔,不過也仍是建議你們看一看文檔,起碼遇到問題時能知道大概查找文檔的一個方向。這樣就會比身邊人強很多。