1. mapping解析
1.1 mapping是什么
- mapping,就是index的type的元数据,每个type都有一个自己的mapping,决定了这个type的数据类型,建立倒排索引的行为,还有进行搜索的行为,可以类比关系型数据库,ES给某个index的type设置mapping,就相当于给一张表定义各个字段的名称和数据类型
- 往一个不存在的index里面插入数据,es会自动建立该index,同时建立type以及对应的mapping
- mapping中就自动定义了每个field的数据类型
- es可以进行dynamic mapping,自动建立mapping,包括自动设置数据类型;也可以提前手动创建index和type的mapping,对各个field进行设置,包括数据类型,包括索引行为,包括分词器,等等
1.2 创建mapping
为空index设置mapping,index需要提前创建好
# ES6.x需要在_mapping后指定type,type可以自动创建
curl -X PUT "node01:9200/nba/_mapping/_doc" -H 'Content-Type:application/json' -d'
{
"properties": {
"name": {
"type": "text"
},
"team_name": {
"type": "text"
},
"position": {
"type": "keyword"
},
"play_year": {
"type": "keyword"
},
"jerse_no": {
"type": "keyword"
}
}
}
'
# ES7.x
curl -X PUT "node01:9200/nba/_mapping" -H 'Content-Type:application/json' -d'
{
"properties": {
"name": {
"type": "text"
},
"team_name": {
"type": "text"
},
"position": {
"type": "keyword"
},
"play_year": {
"type": "keyword"
},
"jerse_no": {
"type": "keyword"
}
}
}
'
创建index的时候设置mapping
# ES6.x
curl -X PUT "node01:9200/index4" -H 'Content-Type:application/json' -d'
{
"mappings": {
"test_type": {
"properties": {
"id": {
"type": "text"
}
}
}
}
}
'
# ES7.x
curl -X PUT "node01:9200/index4" -H 'Content-Type:application/json' -d'
{
"mappings": {
"properties": {
"id": {
"type": "text"
}
}
}
}
'
1.3 查看mapping
查看某个索引的mapping
# ES6.0需要指定type
curl -X GET "node01:9200/nba/_mapping/_doc"
# ES7.0不需要指定type
curl -X GET "node01:9200/nba/_mapping"
{
"nba": {
"mappings": {
"_doc": {
"properties": {
"jerse_no": {
"type": "keyword"
},
"name": {
"type": "text"
},
"play_year": {
"type": "keyword"
},
"position": {
"type": "keyword"
},
"team_name": {
"type": "text"
}
}
}
}
}
}
查看多个索引或者type的mapping
-
ES5.x:一个index可以有多个type
-
查看一个index的一个type的mapping:
curl -X GET "ip:9200/index/_mapping/type"
-
查看一个index的多个type的mapping:
curl -X GET "ip:9200/index/_mapping/type1,type2"
-
查看一个index的所有type的mapping:
curl -X GET "ip:9200/index/_mapping"
-
查看多个index的多个type的mapping:
curl -X GET "ip:9200/index1,index2/_mapping/type1,type2"
这时会做笛卡尔积,把所有可以查到的index的type的mapping返回
-
可以使用通配符:
curl -X GET "ip:9200/index*,test*/_mapping"
curl -X GET "ip:9200/*1,*2/_mapping/type*"
使用通配符也会做笛卡尔积,所有满足通配符的index和type,只要可以这个index有这个type就会查出mapping并返回
-
-
ES6.x:一个index只能有一个type
-
查看一个index的mapping
curl -X GET "ip:9200/index/_mapping/type"
curl -X GET "ip:9200/index/_mapping"
由于只有一个type,所以这两条查询本质上是一样的
-
查看多个index的mapping
curl -X GET "ip:9200/index1,index2/_mapping/type1,type2"
curl -X GET "ip:9200/test*/_mapping"
同样,也是做笛卡尔积,只要可以查出来就返回
-
-
ES7.x:没有type的概念
-
查看多个index的mapping:
curl -X GET "ip:9200/index1,index2/_mapping"
curl -X GET "ip:9200/test*/_mapping"
-
-
ES6.x测试
index和type对应关系:
test_index1/test_type1
test_index2/test_type2
curl -X GET "node01:9200/test_index1/_mapping" { "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index1/_mapping/test_type1" { "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index1,test_index2/_mapping" { "test_index2":{ "mappings":{ "test_type2":{ "properties":{ "name":{ "type":"text" } } } } }, "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type1" { "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type2" { "test_index2":{ "mappings":{ "test_type2":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index1,test_index2/_mapping/test_type1,test_type2" { "test_index2":{ "mappings":{ "test_type2":{ "properties":{ "name":{ "type":"text" } } } } }, "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } } curl -X GET "node01:9200/test_index*,index*/_mapping" { "index3":{ "mappings":{} }, "test_index":{ "mappings":{ "test_type":{ "properties":{ "message":{ "type":"text", "fields":{ "keyword":{ "type":"keyword", "ignore_above":256 } } }, "user":{ "type":"text", "fields":{ "keyword":{ "type":"keyword", "ignore_above":256 } } } } } } }, "test_index2":{ "mappings":{ "test_type2":{ "properties":{ "name":{ "type":"text" } } } } }, "index2":{ "mappings":{} }, "index1":{ "mappings":{ "_doc":{ "properties":{ "jerse_no":{ "type":"keyword" }, "name":{ "type":"text" }, "play_year":{ "type":"keyword" }, "position":{ "type":"keyword" }, "team_name":{ "type":"text" } } } } }, "test_index1":{ "mappings":{ "test_type1":{ "properties":{ "name":{ "type":"text" } } } } } }
查看全部索引的mapping
-
ES5.x/ES6.x
-
查看所有的index的所有的type的mapping
curl -X GET "ip:9200/_mapping
-
查看所有的index的某些type的mapping,没有这个type的index,就不返回它的mapping
curl -X GET "ip:9200/_all/_mapping/type1,type2
-
-
ES7.x
curl -X GET "ip:9200/_mapping"
curl -X GET "ip:9200/_all/_mapping"
-
ES6.x测试
curl -X GET node01:9200/_all/_mapping/test_type1,test_type2
{
"test_index2": {
"mappings": {
"test_type2": {
"properties": {
"name": {
"type": "text"
}
}
}
}
},
"test_index1": {
"mappings": {
"test_type1": {
"properties": {
"name": {
"type": "text"
}
}
}
}
}
}
curl -X GET node01:9200/_mapping
{
"index1": {
"mappings": {
"_doc": {
"properties": {
"jerse_no": {
"type": "keyword"
},
"name": {
"type": "text"
},
"play_year": {
"type": "keyword"
},
"position": {
"type": "keyword"
},
"team_name": {
"type": "text"
}
}
}
}
},
"index2": {
"mappings": {}
},
"test_index2": {
"mappings": {
"test_type2": {
"properties": {
"name": {
"type": "text"
}
}
}
}
},
"test_index": {
"mappings": {
"test_type": {
"properties": {
"message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"user": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
},
"test2": {
"mappings": {}
},
"nba": {
"mappings": {
"_doc": {
"properties": {
"jerse_no": {
"type": "keyword"
},
"name": {
"type": "text"
},
"play_year": {
"type": "keyword"
},
"position": {
"type": "keyword"
},
"team_name": {
"type": "text"
}
}
}
}
},
"test_index1": {
"mappings": {
"test_type1": {
"properties": {
"name": {
"type": "text"
}
}
}
}
},
"test1": {
"mappings": {}
},
"index3": {
"mappings": {}
}
}
1.4 修改mapping
# 只能新增field,不能修改已有field的数据类型
curl -X PUT "node01:9200/test_index1/_mapping/test_type1" -H 'Content-Type:application/json' -d'
{
"properties": {
"id": {
"type": "text"
}
}
}
'
# 如果要写上原有的字段,一定要和以前的数据类型一样
curl -X PUT "node01:9200/test_index1/_mapping/test_type1" -H 'Content-Type:application/json' -d'
{
"properties": {
"id": {
"type": "text"
},
"name": {
"type": "text"
}
}
}
'
# EX7.x不需要指定type
curl -X PUT "node01:9200/test_index1/_mapping" -H 'Content-Type:application/json' -d'
{
"properties": {
"id": {
"type": "text"
}
}
}
'
1.5 mapping其他常用属性总结
PUT index_name
{
"mappings": {
"type_name": {
"_source": {
"enabled": true
},
"_all": {
"enabled": true
},
"dynamic": "strict",
"date_detection": false,
"properties": {
"field_name": {
"type": "type_name", # 指定field的数据类型
"analyzer": "analyzer_name", # 指定field的分词器
"include_in_all": false # 这个field是否包含在_all field中
}
}
}
}
}
-
_all:是否允许将所有field的值拼接在一起,作为一个_all field,建立索引,这样在没有指定任何field进行搜索时,就是使用_all field在搜索,默认true
-
_source:是否保存原始数据,开启后可以带来以下好处,默认开启:
(1) ES搜索默认只会返回id,当_source=false时,需要根据返回的id再去查询一次完整的数据,_source=true时,可以直接拿到完整的数据
(2) ES的更新操作基于_source实现
(3) 索引的重建必须要有_source
(4) 可以基于_source自定义返回的field
(5) 方便于debug
如果不需要上述好处,可以禁用_source
-
dynamic:自动判断数据类型的策略
true:如果document的某个field没有提前设置其类型,就自动识别
false:如果document的某个field没有提前设置其类型,就忽略此field,数据可以插入进去,但在mapping中查不到此field的描述
strict:如果document的某个field没有提前设置其类型,直接报错
-
date_detection:默认会自动按照一定格式识别date,比如yyyy-MM-dd,这样可能会导致一些问题,比如某个field先插入的值为"2017-01-01",那么这个field会自动识别为date类型,后面再插入一个其他类型,例如字符串"hello world"之类的值,就会报错。可以关闭date_detection,如果有需要,手动指定某个field为date类型就可以避免此类问题。
1.6 mapping模板
# 定制化type级别的mapping模板
# 此模板的意思:
# 假如插入的数据的field的名称中包含"title"这个单词,就将其value设置为text类型,且使用ik_max_word分词器分词
# 其他的field则使用dynamic设置的策略来进行数据类型和分词器的初始化
PUT index_name
{
"mappings": {
"type_name": {
"dynamic_templates": [
{
"template_name": {
"match": "*title*",
"match_mapping_type": "text",
"mapping": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
]
}
}
}
# 定制化index级别的mapping模板
# 此模板的意思:
# blog这个这个type的_all=true,其他type的_all=false
PUT my_index
{
"mappings": {
"_default_": {
"_all": { "enabled": false}
},
"blog": {
"_all": { "enabled": true}
}
}
}
2.ES常用的数据类型
2.1 核心数据类型
-
字符串
- text:用于全文检索,该类型的字段将通过分词器进行分词
- keyword:不分词,只能搜索该字段的完整的值
-
数值型
-
byte
-
short
-
integer
-
long
-
float
-
half_float
-
scaled_float
-
double
-
-
布尔
- boolean
-
二进制
- binary:该类型的字段把值当作经过BASE64编码的字符串,默认不存储且不可搜索
-
日期
- date,定义的类型是date,实际需要传入一个字符串或者long值,只要这个字符串满足日期格式,例如"yyyy-MM-dd"或者"yyyy/MM/dd HH:mm:ss",或者这个long值是一个时间戳,就认为是date类型
-
范围类型
-
integer_range、double_range等数值范围
-
date_range
-
例如定义age是一个integer_range
{ "gte": 20, "lte": 40 }
-
2.2 复杂数据类型
- Object:对象类型,可以嵌套
- Array:ES中没有专有的数组类型,使用[]直接定义即可,数组中的元素必须都是同一类型
- 字符串数组:["hello", "world"]
- 整数数组:[0, 1]
- 对象数组:[{"name": "Tom", "age": 12}, {"name": "Jerry", "age": 20}]
3. type底层存储
type,是一个index中用来区分类似的数据的,类似的数据,但是可能有不同的fields,而且有不同的属性来控制索引建立和分词等功能,ES底层的lucene是没有type的概念的,在document中,实际上将type作为一个document的特殊field来存储,即_type,ES通过_type来进行type的过滤和筛选,一个index中的多个type,实际上是放在一起存储的,因此一个index下,type名相同的document,其数据结构和其他设置一定是一样的。
例如以下index:
# 注意:此语句在ES6.x和ES7.x是不能执行的,因为ES6.x只能有一个type,ES7.x移除了type的概念
PUT /my_index
{
"mappings": {
"my_type1": {
"properties": {
"name": {
"type": "keyword"
},
"age": {
"type": "long"
}
}
},
"my_type2": {
"properties": {
"name": {
"type": "keyword"
},
"sex": {
"type": "long"
}
}
}
}
}
# 插入两条document
PUT /my_index/my_type1/1
{
"name": "Tom",
"age": 20
}
PUT /my_index/my_type2/2
{
"name": "Jerry",
"sex": 1
}
# 实际的存储为:
{
"_type": "my_type1"
"name": "Tom",
"age": 20,
"sex": null
}
{
"_type": "my_type2"
"name": "Jerry",
"age": null,
"sex": 1
}
说明:如果使用ES5.x版本,且在同一个index中使用多个type,那么将类似结构的type放在一个index下,这些type应该有多个field是相同的,假如两个type的field完全不同,却放在一个index下,那么就每条数据都会有很多的空值,会带来严重的性能问题。
网友评论