1. 介绍
动态映射(Dynamic Mapping)是指当Elasticsearch遇到文档中之前未遇到的字段,会自动检测及确定字段的数据类型并自动把新字段的类型添加到映射中的过程。
举个例子:
PUT my_index/_doc/1
{ "count": 5 }
执行上面的PUT调用,Elasticsearch会创建一个my_index索引,包含名字为count的字段,字段数据类型为long,并自动把新的字段类型添加到映射中,索引my_index的mapping信息如下所示:
GET my_index/_mappings
{}
# 返回的mapping信息
{
"my_index" : {
"mappings" : {
"properties" : {
"count" : {
"type" : "long"
}
}
}
}
}
动态参数设置
通过设置参数dynamic,可以在文档和对象级别控制动态映射的这种行为,参数dynamic可以设置为下列三种值:
(1)true:将新的检测到的字段添加到映射中。(默认)
(2)false:忽略新检测到的字段。这些字段将不会被索引,因此不能被搜索,但仍然会出现在返回命中的_source字段中。这些字段将不会添加到映射中,新的字段必须显式添加。
(3)strict:如果检测到新字段,则抛出异常并拒绝索引文档。新字段必须显式地添加到映射中。
- 操作示例如下:
# 1 - dynamic设置为strict,并且是类型级别,表示不会动态添加top级字段
# 2 - user 对象继承类型级别设置
# 3 - dynamic设置为true,并且是对象级别,表示social_networks对象可以动态添加字段
PUT my_index
{
"mappings": {
"dynamic": "strict", // 1
"properties": {
"user": { // 2
"properties": {
"social_networks": {
"dynamic": "true", // 3
"properties": {}
}
}
}
}
}
}
如果启用了动态字段映射,Elasticsearch采用一些规则来确定JSON字段对应的数据类型,规则包括动态字段映射(Dynamic field mappings)和动态模板集(Dynamic templates)。
2. 动态字段映射
动态字段映射(Dynamic field mappings):动态字段的检测映射规则。
动态字段映射规则
JSON数据类型 | Elasticsearch数据类型 |
---|---|
null | 无字段添加 |
true或false | boolean类型 |
浮点数 | float类型 |
整数 | long类型 |
对象 | object类型 |
数组 | 取决于数组中第一个非空值 |
字符串 | date类型(日期检测)、double类型、 long类型(数字检测)、text类型、 keyword 类型 |
只有上面这些数据类型会被动态检测,所有其他数据类型必须显式地映射。
日期检测
如果启用了date_detection(默认启用),那么将检查新的字符串字段,看它们的内容是否匹配dynamic_date_formats中指定的任何日期模式。如果找到匹配项,将添加相应格式的一个新日期字段。
- 参数dynamic_date_formats 默认格式为
[ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
举个例子:
# 创建索引,未指定字段类型
PUT my_index_01/_doc/1
{"create_date":"2015/09/02"}
# 查看索引的映射
GET my_index_01/_mapping
# 返回结果,表示已经动态映射为日期类型
{
"my_index_01" : {
"mappings" : {
"properties" : {
"create_date" : {
"type" : "date",
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
}
}
}
}
}
禁用日期检测
如果禁用了日期检测,那么Elasticsearch遇到日期格式的字符串,会动态映射到其他类型(text或keyword),通过设置参数date_detection等于false来禁用动态日期检测。示例如下:
# 禁用date_detection
PUT my_index_01
{"mappings":{"date_detection":false}}
# 创建索引,未指定字段类型
PUT my_index_01/_doc/1
{"create_date":"2015/09/02"}
# 查看索引的映射
GET my_index_01/_mapping
# 返回结果,表示已经动态映射为text类型
{
"my_index_01" : {
"mappings" : {
"date_detection" : false,
"properties" : {
"create_date" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
自定义检测日期格式
可以自定义动态检测的日期格式。示例如下:
PUT my_index_01
{"mappings":{"dynamic_date_formats":["MM/dd/yyyy"]}}
数字检测
虽然JSON支持本地浮点数和整数数据类型,但一些应用程序或语言有时可能将数字呈现为字符串。通常正确的解决方案是显式映射这些字段,但数字检测(默认禁用)可以自动做到这一点,示例如下:
# 开启数字检测
PUT my_index_01
{"mappings":{"numeric_detection":true}}
PUT my_index_01/_doc/1
{"my_float":"1.0","my_integer":"1"}
GET my_index_01/_mapping
{}
# 返回结果,字段 my_float 映射为float类型,字段 my_integer 映射为long类型
{
"my_index_01" : {
"mappings" : {
"numeric_detection" : true,
"properties" : {
"my_float" : {
"type" : "float"
},
"my_integer" : {
"type" : "long"
}
}
}
}
}
3. 动态模板集
动态模板集(Dynamic templates):用于自定义规则来为动态添加的字段配置映射。
动态模板集是一个命名object类型的数组,包含至少一个动态模板,结构示例如下:
# 双斜线在执行时需要去掉
PUT my_index_01
{
"mappings": {
"dynamic_templates": [ //1
{
"integers": { // 2
"match_mapping_type": "long", //3
"mapping": { // 4
"type": "integer"
}
}
}
]
}
}
- 注释1-动态模板集参数名为dynamic_templates,数据类型是支持object的数组。
- 注释2-动态模板名称自定义。
- 注释3-匹配条件,包括
match_mapping_type, match, match_pattern, unmatch, path_match, path_unmatch
。 - 注释4-匹配字段使用的类型映射。
动态模板集包含几类重要参数:
(1)match_mapping_type作用于检测数据类型。
(2)match和unmatch或match_pattern作用于字段的名称。
(3)path_match和path_unmatch作用于字段的完整点路径。
可以在动态模板集中的映射使用占位符{name}和{dynamic_type}, {name}表示原始字段名,{dynamic_type}表示检测到的数据类型。
验证动态模板集
在建立索引应用动态模板集或更新动态模板集时,Elasticsearch会对动态模板集的映射片段进行验证,验证流程如下:
如果在映射片段中使用了{name}占位符,则在更新动态模板集时跳过验证,这是因为更新时字段名是未知的。但是在建立索引时应用模板时会进行验证。
处理动态模板集
- 如果动态模板集中存在多个模板时,会按照顺序处理模板,第一个匹配的模板将会使用。
- 当通过put mapping API放置新的动态模板集时,所有现有的模板都会被覆盖。并且允许动态模板集在添加后被重新排序或删除。
match_mapping_type
- match_mapping_type对应的值是JSON解析器检测到的数据类型。因为JSON不区分long和integer或者double和float,所以它总是选择更宽的数据类型,比如long表示整数,double表示浮点数。
- match_mapping_type数据类型有下列几种会被自动检测到:
- 当值为true或false时,类型为boolean。
- 当启用日期检测并找到与任何配置的日期格式匹配的字符串值时,类型为date。
- 当值有小数部分的数字,类型为double。
- 当值没有小数部分的数字,类型为long。
- 当值为对象或散列结构时,类型为object。
- 当值为字符串时,类型为string。
此外,符号*可以用于匹配所有数据类型。
例如,将所有整数字段映射为integer类型而不是long类型,将所有字符串字段映射为text类型和keyword类型,可使用以下模板:
PUT my_index_01
{
"mappings": {
"dynamic_templates": [
{
"template1": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"template2": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
}
PUT my_index_01/_doc/1
{"my_integer":5,"my_string":"Some string"}
match和unmatch
- match参数使用模式对字段名进行匹配,而unmatch使用模式来排除通过match匹配的字段。
例如,匹配所有字段名称以long_开头的字符串字段(排除以_text结尾的),并将它们映射为long字段,可使用以下模板:
PUT my_index_01
{
"mappings": {
"dynamic_templates": [
{
"longs_as_strings": {
"match_mapping_type": "string",
"match": "long_*",
"unmatch": "*_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
PUT my_index_01/_doc/1
{"long_num":"5","long_text":"foo"}
match_pattern
- match_pattern参数用来调整match参数的行为,可以在字段名上支持完整的Java正则表达式匹配,例如:
PUT my_index_01
{
"mappings": {
"dynamic_templates": [
{
"pattern_as_strings": {
"match_mapping_type": "string",
"match_pattern": "regex",
"match": "^long_\\d+$",
"mapping": {
"type": "long"
}
}
}
]
}
}
# 字段long_1映射为long类型,字段long_text映射为text或keyword类型
PUT my_index_01/_doc/1
{"long_1":"5","long_text":"foo"}
path_match和path_unmatch
- path_match和path_unmatch参数的工作方式与match和unmatch相同,但操作在字段的完整点路径上,而不仅仅是字段名称。
例如:
PUT my_index_01
{
"mappings": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT my_index_01/_doc/1
{"name":{"first":"John","middle":"Winston","last":"Lennon"}}
上面例子将字段名为name的对象中所有子级字段(排除子级middle字段)的值复制到顶层的full_name字段,创建新的字段full_name,复制内容到full_name字段中,但是不会影响_source字段内容。
{name}和{dynamic_type}
占位符{name}被替换为字段名,占位符{dynamic_type}被替换为检测到的动态字段类型。
例如,将所有字符串字段设置为使用与字段同名的分析器,并对所有非字符串字段禁用doc_values,可使用以下模板:
PUT my_index_01
{
"mappings": {
"dynamic_templates": [
{
"named_analyzers": {
"match_mapping_type": "string",
"match": "*",
"mapping": {
"type": "text",
"analyzer": "{name}"
}
}
},
{
"no_doc_values": {
"match_mapping_type": "*",
"mapping": {
"type": "{dynamic_type}",
"doc_values": false
}
}
}
]
}
}
# english字段被映射为english分析器的text类型字段。
# count字段被映射为禁用doc_values的long类型字段。
PUT my_index_01/_doc/1
{"english":"Some English text","count":5}
4. 结语
Elasticsearch的动态映射功能已完成了基本介绍,后续在应用环境中需要根据实际情况灵活运用。