Elasticsearch系列(6)Mapping之动态映射

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的动态映射功能已完成了基本介绍,后续在应用环境中需要根据实际情况灵活运用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350