一、动态映射
刚开始学ES时感觉它与MySQL相比,有个明显不同:ES不需要先定义表结构
就可以插入数据了。
我们不用先创建index和mapping,直接put数据后,ES会自动帮我们创建index和mapping。
这个功能虽然看着比较方便,但是有时也会给我们带来困扰,因为ES自动创建的mapping中的字段类型不一定是我们期望的。所以掌握好ES的Mapping的知识是在工作中使用ES的基础。
ES的mappings设置选项中,有个dynamic
,它是控制是否接收以及如何处理新的字段,它有四个值可选:
PUT pigg_map_test
{
"mappings": {
"dynamic": runtime
}
}
dynamic值 | 说明 |
true | 添加新字段到mapping中,这个是 |
runtime | 新字段将作为runtime fields添加到mapping,这些字段不会被索引,查询时会从_source中加载出来 |
false | 新添加的字段会被忽略,这些新字段不会被索引,所以也不支持检索 |
strict | 严格模式,当有新字段时,会报错 |
这个dynamic
参数一般也就采用默认值true
。它有2个优点:
- 容错率高,即使没有为新字段设置mapping,也会存储,哪怕类型不对,后期可以同步到类型对的字段上,这样保证了客户的数据没有丢失。在企业开发中,丢了重要的数据可能就得提桶跑路了。
- 别的同事来处理这个功能也比较熟悉,如果你设置成别的选项,别人再接手时可能感觉掉进一个坑里,因为他可能对这些配置并不是那么熟悉。
注意:下面讲的动态字段映射
,还是以dynamic
为true
的基础上继续讨论。
二、动态字段映射
当ES接收到新的字段,它会自动为新字段创建类型,我们要熟悉ES自动创建类型的规律。
下面给出插入文档中JSON数据类型到ES数据类型的一个映射表。
JSON数据类型 | ES数据类型 |
null | 不添加字段 |
true / false | boolean |
double | float |
long | long |
object | object |
array | 根据数组中第一个非null值的类型 |
通过日期检测的string | date |
通过数字检测的string | float 或 long |
没有通过上面2个检测的string | 带 |
下面我们来对上表格中每一项都依次验证下。
1 null
插入一个文档,name的值为null,然后再验证mapping
PUT pigg_map_test/_doc/1
{
"name": null
}
GET pigg_map_test/_mapping返回如下,看出null值是不会添加字段的
{
"pigg_map_test" : {
"mappings" : { }
}
}
2 true / false
插入一个文档,state的值为true,然后再验证mapping
PUT pigg_map_test/_doc/1
{
"state": true
}
GET pigg_map_test/_mapping返回如下,看出布尔值会设置为boolean
类型
{
"pigg_map_test" : {
"mappings" : {
"properties" : {
"state" : {
"type" : "boolean"
}
}
}
}
}
3 double & long 数字
PUT pigg_map_test/_doc/1
{
"price": 1.0000,
"count": 10000
}
GET pigg_map_test/_mapping返回如下:
{
"pigg_map_test" : {
"mappings" : {
"properties" : {
"count" : {
"type" : "long"
},
"price" : {
"type" : "float"
}
}
}
}
}
4 object
给文档添加1个objcet
PUT pigg_map_test/_doc/1
{
"user": {
"name": "江苏最菜亚瑟",
"salary": 33000.00
}
}
mapping如下,dynamic
为true
有这样的好处,如果设置dynamic
为runtime
,则不会为object添加字段
{
"pigg_map_test" : {
"mappings" : {
"properties" : {
"user" : {
"properties" : {
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"salary" : {
"type" : "float"
}
}
}
}
}
}
}
5 array
插入一个数组,mapping的字段类型以第一个非null值的类型
PUT pigg_map_test/_doc/1
{
"hero": [ null, 1, 2]
}
mapping如下:
{
"pigg_map_test" : {
"mappings" : {
"properties" : {
"hero" : {
"type" : "long"
}
}
}
}
}
数组中数据类型得一致,下面数组同时包含1和2.2,这样文档会保存失败的
PUT pigg_map_test/_doc/1
{
"hero": [ null, 1, 2.2]
}
6 时间格式的string
关于ES的日期格式,可以参考我之前的博客详解mapping之date date_nanos 注意第三个日期类型是yyyy-MM-ddTHH:mm:ss
PUT pigg_map_test/_doc/1
{
"date1": "2022-08-25",
"date2": "2022/08/25",
"date3": "2022-08-25T13:25:01"
}
mapping如下,上面3个确实都转成date类型了
{
"pigg_map_test" : {
"mappings" : {
"properties" : {
"date1" : {
"type" : "date"
},
"date2" : {
"type" : "date",
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
},
"date3" : {
"type" : "date"
}
}
}
}
}
6.1 定制日期格式
我们还可以定制自己想要的日期格式,在mappings
中设置dynamic_date_formats
,ES会把符合格式的字符串设置为date类型。
PUT pigg_map_test
{
"mappings": {
"dynamic_date_formats": ["yyyy-MM-dd", "yyyy/MM/dd", "yyyy-MM-dd HH:mm:ss"]
}
}
创建文档中3个字段分别对应上面设置的3个日期格式
PUT pigg_map_test/_doc/1
{
"date1": "2022-08-25",
"date2": "2022/08/25",
"date3": "2022-08-25 13:25:01"
}
mapping如下:
{
"pigg_map_test" : {
"mappings" : {
"dynamic_date_formats" : [
"yyyy-MM-dd",
"yyyy/MM/dd",
"yyyy-MM-dd HH:mm:ss"
],
"properties" : {
"date1" : {
"type" : "date",
"format" : "yyyy-MM-dd"
},
"date2" : {
"type" : "date",
"format" : "yyyy/MM/dd"
},
"date3" : {
"type" : "date",
"format" : "yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
7 数字格式的string
ES默认会把数字格式的string也设置为text类型,比如下面例子
PUT pigg_map_test/_doc/1
{
"age": "30",
"salary": "35000.00"
}
mapping中age和salary都会是text
类型,如果要数字格式的字符串也按照数字格式保存,需要设置如下
PUT pigg_map_test
{
"mappings": {
"numeric_detection": true
}
}
再插入上面文档,会发现字段类型会是数字类型:
{
"pigg_map_test" : {
"mappings" : {
"numeric_detection" : true,
"properties" : {
"age" : {
"type" : "long"
},
"salary" : {
"type" : "float"
}
}
}
}
}
三、结语
在实际企业开发中,都会提前设置好mapping的,不会完全让ES自动设置字段类型的。但是掌握好动态字段映射还是很重要的,是学习mapping的前提条件。
- 在字段类型比较确定时,可以先设置好mapping,再插入数据,有新字段时,先给mapping添加新的字段设置
- 在字段的个数和类型都不确定时,可以使用mapping的
动态模板
,按照已经指定的规则设置它的类型。比如某个字段名为int_age
,就让类型为integer
,字段名为float_price
就设为float
。
好好学习,天天向上,下一篇博客会写mapping的动态模板
的内容。