1.什么是Mapping
Mapping 类似 mysql 中的 schema 的定义
用于定义索引属性字段的名称、字段的数据类型 (如 text , long , keyword…)、字段的倒排索引相关配置
一个Mapping 属于一个索引的Type、每个文档都属于一个Type
es7.0开始, 在Mapping中不需要指定 Type信息, 因为7.0之后只有_doc Type
2.自动创建Mapping
当我们去创建一个 索引的时候 未指定 mapping , es会默认帮这个索引创建一个 mapping
例:创建一个索引testmapping
创建一个空索引:
PUT testmapping
创建成功:
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "testmapping"
}
查询该索引mapping信息:
GET testmapping/_mapping
返回结果:
{
"testmapping" : {
"mappings" : { }
}
}
此时可以看到ES为我们创建了一个空mapping的索引,如果我们在创建索引的时候指定字段,ES也会生成我们指定的字段类型,或者默认的类型
创建名为user的索引,并指定字段及字段类型
PUT /user
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"language": {
"type": "keyword"
},
"price": {
"type": "double"
},
"publish_time": {
"type": "date",
"format": "yyy-MM-dd"
}
}
}
}
获取user的mapping信息
GET user/_mapping
{
"user" : {
"mappings" : {
"properties" : {
"language" : {
"type" : "keyword"
},
"price" : {
"type" : "double"
},
"publish_time" : {
"type" : "date",
"format" : "yyy-MM-dd"
},
"title" : {
"type" : "text",
"analyzer" : "ik_max_word"
}
}
}
}
}
动态映射(dynamic mapping)
关系型数据库: 先创建表 => 指定字段和字段类型 => 数据写入表
在ES中,索引就相当于表,文档就相当于记录,文档里面的字段就相当于表的字段,字段同样有数据类型。mapping就用来定义文档有哪些字段,这些字段如何存储和索引。
ES与关系型数据库不同之处在于: 其不需要先定义表结构,而可以根据写入文档的内容,来推断字段和数据类型,创建索引结构,这就是dynamic mapping,动态映射的由来。这提供了极大的灵活性。
注:一个索引的字段数量有上限的,超过上限就会报错(默认单个索引创建最大1000个字段)
dynamic参数设置:
按dynamic值,可分为下面三种模式
动态模式(dynamic:true),根据输入文档的内容,自动推断字段和类型,创建mapping
非动态模式(dynamic:false),无法根据输入文档的内容,自动创建mapping,需要手动创建mapping
严格模式(dynamic:strict),同非动态模式,区别在于,非动态模式,输入的文档中如果有字段不在mapping中,依然可以存储和读取,但是该字段不在mapping中,因此也无法根据该字段进行检索;但严格模式,无法存储,会直接报错,严格模式实际上就类似于关系型数据库中的表了。
1.动态模式
直接对一个不存在的索引插入一条数据
POST dynamictrue/_doc
{
"name": "张三",
"age": 15
}
插入成功,获取该索引的mapping信息
GET dynamictrue/_mapping
{
"dynamictrue" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
在动态模式下,ES会根据插入的数据自动生成对应的字段类型,也可以通过动态模板(dynamic template)来覆盖这个规则,实现自定义推测规则,具体可以参考ES官网
1.1动态模式下索引文档
GET dynamictrue/_search
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamictrue",
"_type" : "_doc",
"_id" : "ulYk54wBAEWV3dbHq4Dj",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论: 动态模式下索引文档是有数据返回的
1.2动态模式下索引字段
-- 查询当前索引下age是15的数据
GET dynamictrue/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"age": {
"value": 15
}
}
}
]
}
}
}
返回值:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamictrue",
"_type" : "_doc",
"_id" : "ulYk54wBAEWV3dbHq4Dj",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论: 动态模式下索引字段也是可以的
1.3动态模式下变更Mapping
新增一个字段
POST dynamictrue/_doc
{
"addr": "地址"
}
成功新增名为addr的字段
GET dynamictrue/_mapping
{
"dynamictrue" : {
"mappings" : {
"properties" : {
"addr" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
2.非动态模式
新建一个索引(dynamicfalse)并设置dynamic为false
PUT dynamicfalse
{
"settings": {
"index": {
"number_of_shards": "5",
"number_of_replicas": "1"
}
},
"mappings": {
"dynamic": false,
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
查询索引(dynamicfalse)的mapping信息
GET dynamicfalse/_mapping
{
"dynamicfalse" : {
"mappings" : {
"dynamic" : "false",
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
}
此时可以看到返回结果中dynamic已经被设置成false了
此时我们对该索引新增一条数据
POST dynamicfalse/_doc
{
"name": "张三",
"age": 15
}
2.1非动态模式下索引文档
GET dynamicfalse/_search
查询结果:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamicfalse",
"_type" : "_doc",
"_id" : "hFYi54wBAEWV3dbHdYDM",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论: 非动态模式下索引文档是有数据返回的
2.2非动态模式下索引字段
GET dynamicfalse/_search
{
"query": {
"match": {
"age": 15
}
}
}
返回结果:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamicfalse",
"_type" : "_doc",
"_id" : "z1a154wBAEWV3dbHQYzt",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论: 非动态模式下索引字段是可以的,但是只针对查询在mapping中存在的字段生效,如果字段不存在mapping,无法生效,请往下看↓
2.3非动态模式下变更Mapping
在当前索引中插入一个addr字段的数据
POST dynamicfalse/_doc
{
"addr": "地址"
}
插入成功后,查询当前索引mapping信息
GET dynamicfalse/_mapping
{
"dynamicfalse" : {
"mappings" : {
"dynamic" : "false",
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
}
可以发现非动态模式下新增的字段并没有在mapping中生成
此时查询当前索引中数据
GET dynamicfalse/_search
返回数据如下:
{
"took" : 537,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamicfalse",
"_type" : "_doc",
"_id" : "cVa654wBAEWV3dbHtI3g",
"_score" : 1.0,
"_source" : {
"addr" : "地址"
}
},
{
"_index" : "dynamicfalse",
"_type" : "_doc",
"_id" : "z1a154wBAEWV3dbHQYzt",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
此时可以发现addr为地址的数据已经成功插入到了当前索引中
此时再根据addr字段索引数据
GET dynamicfalse/_search
{
"query": {
"match": {
"addr": "地址"
}
}
}
返回结果如下:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
结论: 非动态模式下变更mapping是无法在mapping中生成的,新增的数据虽然可以存储,但是无法被新增的字段索引,只能根据文档索引或者已存在mapping中的字段索引所带出
3.严格模式
新建一个索引(dynamicfalse)并设置dynamic为strict
PUT dynamicstrict
{
"settings": {
"index": {
"number_of_shards": "5",
"number_of_replicas": "1"
}
},
"mappings": {
"dynamic": "strict",
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
}
}
}
}
查询当前索引(dynamicstrict)的mapping信息
GET dynamicstrict/_mapping
{
"dynamicstrict" : {
"mappings" : {
"dynamic" : "strict",
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
}
新增一条数据
POST dynamicstrict/_doc
{
"name": "张三",
"age": 15
}
3.1严格模式下索引文档
GET dynamicstrict/_search
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "dynamicstrict",
"_type" : "_doc",
"_id" : "-1bS54wBAEWV3dbH3I99",
"_score" : 1.0,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论: 严格模式下索引文档是可以的
3.2严格模式下索引字段
GET dynamicstrict/_search
{
"query": {
"match": {
"name": "张三"
}
}
}
返回结果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.5753642,
"hits" : [
{
"_index" : "dynamicstrict",
"_type" : "_doc",
"_id" : "-1bS54wBAEWV3dbH3I99",
"_score" : 0.5753642,
"_source" : {
"name" : "张三",
"age" : 15
}
}
]
}
}
结论:严格模式下索引mapping中存在的字段也是可以的
3.3严格模式下变更Mapping
POST dynamicstrict/_doc
{
"addr": "地址"
}
返回报错信息如下:
{
"error" : {
"root_cause" : [
{
"type" : "strict_dynamic_mapping_exception",
"reason" : "mapping set to strict, dynamic introduction of [addr] within [_doc] is not allowed"
}
],
"type" : "strict_dynamic_mapping_exception",
"reason" : "mapping set to strict, dynamic introduction of [addr] within [_doc] is not allowed"
},
"status" : 400
}
结论: 严格模式下无法新增字段,此模式可以用于在工作中防止自己的索引字段被人修改