版本:Elasticsearch 6.2.4。
Mapping類似於數據庫中的表結構定義,主要作用如下:
- 定義Index下字段名(Field Name)
- 定義字段的類型,比如數值型,字符串型、布爾型等
- 定義倒排索引的相關配置,比如是否索引、記錄postion等
Mapping完整的內容可以分為四部分內容:
- 字段類型(Field datatypes)
- 元字段(Meta-Fields)
- Mapping參數配置(Mapping parameters)
- 動態Mapping(Dynamic Mapping)
自動Mapping
如果沒有手動設置Mapping,Elasticsearch默認會自動解析出類型,且每個字段以第一次出現的為准。
下面我們先看一下Elasticsearch默認創建的Mapping是什么樣的。
首先我們創建一個索引:
PUT /user/
查詢索引信息:
GET /user
結果:
{
"user": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1540044686190",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "_K5b8w7jRiuthf7QeQZhdw",
"version": {
"created": "5060299"
},
"provided_name": "user"
}
}
}
}
增加一條數據:
PUT /user/doc/1
{
"name":"Allen Yer",
"job":"php",
"age":22
}
PUT /user/doc/2
{
"name":"Allen Yer",
"job":0,
"age":22
}
查詢數據是否新增成功:
GET /user/doc/_count
結果:
{
"count": 2,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
}
}
count為2,說明新增成功。然后我們查詢下 mapping :
{
"user": {
"mappings": {
"doc": {
"properties": {
"age": {
"type": "long"
},
"job": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
發現自動為每個字段設置了類型:
- name: text類型,另外額外增加了
name.keyword
字段,keyword
類型; - job:text類型,另外額外增加了
job.keyword
字段,keyword
類型;雖然第二次數據新增是數字類型,但還是以第一次為主; - age:long類型。
大家可以把索引刪掉,將新增數據調整為先新增第2條,再新增第一條,發現報錯了:
DELETE /user
PUT /user/doc/2
{
"name":"Allen Yer",
"job":0,
"age":22
}
PUT /user/doc/1
{
"name":"Allen Yer",
"job":"php",
"age":22
}
報錯:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse [job]"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse [job]",
"caused_by": {
"type": "number_format_exception",
"reason": "For input string: \"php\""
}
},
"status": 400
}
也能說明以第一次為主以字段第一次的值類型為准。這也說明了默認創建mapping可能不是我們想要的,這就需要手動創建mapping,好處有:
- 提前指定字段(通過設置甚至可以達到禁止自動增加字段的效果)
- 合理設置字段類型,防止分詞過多或者解析不合理。分詞過大會導致磁盤空間占用大。
手動創建mapping
這次我們刪掉mapping,並手動創建一個:
DELETE /user
PUT /user/
{
"mappings": {
"doc": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"age": {
"type": "long",
"index": false
},
"job": {
"type": "keyword"
},
"intro":{
"type":"text"
},
"create_time": {
"type": "date",
"format": "epoch_second"
}
}
}
}
}
字段類型說明:
- name:text類型,會進行分詞,支持模糊檢索。
- name.keyword : 這相當於是嵌套了一個字段,keyword類型,只能精確匹配,不支持分詞。超過256字符長度不索引,也就沒法搜索到。
- age:long類型,支持精確匹配。
- job:keyword類型,只能精確匹配,不支持分詞。
- intro:text類型,會進行分詞,支持模糊檢索。
- create_time:date類型,支持10位時間戳。
注意:mapping生成后是不允許修改(包括刪除)的。所以需要提前合理的的定義mapping。
字段類型
Elasticsearch支持文檔中字段的許多不同數據類型:
普通數據類型
字符串類型
有text
和 keyword
2種 。其中 text
支持分詞,用於全文搜索;keyword
不支持分詞,用於聚合和排序。在舊的ES里這兩個類型由string
表示。
如果安裝了IK分詞插件,我們可以為text
類型指定IK分詞器。一般來說,對於字符串類型,如果:
- 模糊搜索+精確匹配,一般是name或者title字段:
"name": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
- 模糊搜索,一般是內容詳情字段:
"content": {
"type": "text",
"analyzer": "ik_smart"
}
- 精確匹配:
"name": {
"type": "keyword"
}
- 不需要索引:
"url": {
"type": "keyword",
"index": false
}
數字類型
支持 long,integer,short,byte,double,float,half_float,scaled_float。具體說明如下:
-
long
帶符號的64位整數,其最小值為-2^63
,最大值為(2^63)-1
。 -
integer
帶符號的32位整數,其最小值為-2^31
,最大值為(23^1)-1
。 -
short
帶符號的16位整數,其最小值為-32,768,最大值為32,767。 -
byte
帶符號的8位整數,其最小值為-128,最大值為127。 -
double
雙精度64位IEEE 754浮點數。 -
float
單精度32位IEEE 754浮點數。 -
half_float
半精度16位IEEE 754浮點數。 -
scaled_float
縮放類型的的浮點數。需同時配置縮放因子(scaling_factor)一起使用。
對於整數類型(byte,short,integer和long)而言,我們應該選擇這是足以使用的最小的類型。這將有助於索引和搜索更有效。
對於浮點類型(float、half_float和scaled_float),-0.0
和+0.0
是不同的值,使用term
查詢查找-0.0
不會匹配+0.0
,同樣range
查詢中上邊界是-0.0
不會匹配+0.0
,下邊界是+0.0
不會匹配-0.0
。
其中scaled_float
,比如價格只需要精確到分,price
為57.34
的字段縮放因子為100
,存起來就是5734
。優先考慮使用帶縮放因子的scaled_float
浮點類型。
示例:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"status": {
"type": "byte"
},
"year": {
"type": "short"
},
"id": {
"type": "long"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
}
}
}
}
}
日期類型
類型為 date
。
JSON本身是沒有日期類型的,因此Elasticsearch中的日期可以是:
- 包含格式化日期的字符串。
- 一個13位long類型表示的毫秒時間戳( milliseconds-since-the-epoch)。
- 一個integer類型表示的10位普通時間戳(seconds-since-the-epoch)。
在Elasticsearch內部,日期類型會被轉換為UTC(如果指定了時區)並存儲為long類型表示的毫秒時間戳。
日期類型可以使用使用format
自定義,默認缺省值:"strict_date_optional_time||epoch_millis"
:
"postdate": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
}
format
有很多內置類型,這里列舉部分說明:
- strict_date_optional_time, date_optional_time
通用的ISO日期格式,其中日期部分是必需的,時間部分是可選的。例如 "2015-01-01"或"2015/01/01 12:10:30"。 - epoch_millis
13位毫秒時間戳 - epoch_second
10位普通時間戳
其中strict_
開頭的表示嚴格的日期格式,這意味着,年、月、日部分必須具有前置0。
當然也可以自定義日期格式,例如:
"postdate":{
"type":"date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
}
注意:如果新文檔的字段的值與format里設置的類型不兼容,ES會返回失敗。示例:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type": "date",
"format":"epoch_millis"
}
}
}
}
}
PUT my_index/_doc/1
{
"date":1543151405000
}
PUT my_index/_doc/2
{
"date":1543151405
}
PUT my_index/_doc/3
{
"date":"2018-11-25 21:10:43"
}
GET my_index/_doc/_search
第3條數據插入失敗,因為只接受長整數的時間戳,字符串類型的日期是不匹配的。第2條的值只有10位數,雖然值是不正確的,但是在epoch_millis
的取值范圍內,所以也是成功的。
布爾類型
類型為 boolean
。
二進制類型
類型為 binary
。
范圍類型
integer_range,float_range,long_range,double_range,date_range
復雜類型
- 數組數據類型
在ElasticSearch中,沒有專門的數組(Array)數據類型,但是,在默認情況下,任意一個字段都可以包含0或多個值,這意味着每個字段默認都是數組類型,只不過,數組類型的各個元素值的數據類型必須相同。在ElasticSearch中,數組是開箱即用的(out of box),不需要進行任何配置,就可以直接使用。,例如:
字符型數組: [ "one", "two" ]
整型數組:[ 1, 2 ]
數組型數組:[ 1, [ 2, 3 ]]
等價於[ 1, 2, 3 ]
-
對象數據類型
object 對於單個JSON對象。JSON天生具有層級關系,文檔可以包含嵌套的對象。 -
嵌套數據類型
nested 對於JSON對象的數組
Geo數據類型
-
地理點數據類型
geo_point 對於緯度/經度點 -
Geo-Shape數據類型
geo_shape 對於像多邊形這樣的復雜形狀
專用數據類型
-
IP數據類型
ip 用於IPv4和IPv6地址 -
完成數據類型
completion 提供自動完成的建議 -
令牌計數數據類型
token_count 計算字符串中的標記數 -
mapper-murmur3
murmur3 在索引時計算值的哈希值並將它們存儲在索引中 -
過濾器類型
接受來自query-dsl的查詢 -
join 數據類型
為同一索引中的文檔定義父/子關系
多字段
為不同目的以不同方式索引相同字段通常很有用。例如,string可以將字段映射為text用於全文搜索的keyword字段,以及用於排序或聚合的字段。或者,您可以使用standard分析儀, english分析儀和 french分析儀索引文本字段。
元字段
_all
該字段用於在沒有指定具體字段的情況下進行模糊搜索,可以搜索全部字段的內容。
原理是將所有字段的內容視為字符串,拼在一起放在一個_all
字段上,但這個字段默認是不被存儲的,可以被搜索。在query_string
與 simple_query_string
查詢(Kibana搜索框用的這種查詢方式)默認也是查詢_all
字段。
6.x
版本被默認關閉。
相關設置:
PUT my_index
{
"mappings": {
"my_type": {
"_all": {
"enabled": true,
"store": false
},
"properties": {}
}
},
"settings": {
"index.query.default_field": "_all"
}
}
上述配置在5.x
版本是默認配置:
- 默認開啟
_all
字段 - 默認不存儲
_all
字段 - 默認搜索
_all
字段
如果從CPU性能及磁盤空間考慮,可以考慮可以完全禁用或基於每個字段自定義_all
字段。
假設_all
字段被禁用,則URI搜索請求、 query_string
和simple_query_string
查詢將無法將其用於查詢。我們可以將它們配置為其他字段:通過定義 index.query.default_field
屬性。
_source
這個字段用於存儲原始的JSON文檔內容,本身不會被索引,但是搜索的時候被返回。如果沒有該字段,雖然還能正常搜索,但是返回的內容不知道對應的是什么。
示例:
GET /user/doc/_search?q=name
結果:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "user",
"_type": "doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "this is test name",
"age": 22,
"job": "java",
"intro": "the intro can not be searched by singal",
"intro2": "去朝陽公園",
"create_time": 1540047542
}
}
]
}
}
搜索結果就包含_source
字段,存儲的是原始文檔內容。如果被禁用,只知道有匹配內容,但是無法知道返回的是什么。所以需要謹慎關閉該字段。
如果想禁用該字段,可以在創建Mapping的時候,設置_:
{
"mappings": {
"_doc": {
"_source": {
"enabled": false
}
}
}
}
_type
ElasticSearch里面有 index 和 type 的概念:index稱為索引,type為文檔類型,一個index下面有多個type,每個type的字段可以不一樣。這類似於關系型數據庫的 database 和 table 的概念。
但是,ES中不同type下名稱相同的filed最終在Lucene中的處理方式是一樣的。所以后來ElasticSearch團隊想去掉type,於是在6.x版本為了向下兼容,一個index只允許有一個type。
該字段再在6.0.0中棄用。在Elasticsearch 6.x 版本中創建的索引只能包含單個type。在5.x中創建的含有多個type的索引將繼續像以前一樣在Elasticsearch 6.x中運行。type 將在Elasticsearch 7.0.0中完全刪除。
詳見:https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html
參考
1、Mapping | Elasticsearch Reference [6.4] | Elastic
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
2、Elasticsearch 6.x Mapping設置 - 小旋鋒
https://mp.weixin.qq.com/s/pBPH-wccdY1oslpqGgAHBg
3、整理的es中的mapping方面的內容 - 辛星,前進的路上. - CSDN博客
https://blog.csdn.net/xinguimeng/article/details/51588583
4、[譯]ElasticSearch數據類型--string類型已死, 字符串數據永生 - 牧曦之晨 - SegmentFault 思否
https://segmentfault.com/a/1190000008897731
5、ElasticSearch的_all域 | 學步園
https://www.xuebuyuan.com/2053874.html
6、圖解Elasticsearch中的_source、_all、store和index屬性 - 1.01^365=37.78 (Lucene、ES、ELK開發交流群: 370734940) - CSDN博客
https://blog.csdn.net/napoay/article/details/62233031
7、Elasticsearch - 自動檢測及動態映射Dynamic Mapping - 上善若水,水善利萬物而不爭。 - CSDN博客
https://blog.csdn.net/xifeijian/article/details/51090338
8、Field datatypes | Elasticsearch Reference [6.2] | Elastic
https://www.elastic.co/guide/en/elasticsearch/reference/6.2/mapping-types.html