如果你想在运行时增加新的字段,你可能会启用动态映射。然而,有时候,动态映射的规则可能不太智能。幸运的是,我们可以通过设置去自定义这些规则,以便更好的适用于你的数据。
使用 dynamic_templates 可以完全控制新的字段的映射类型, 甚至可以通过匹配字段名称或数据类型来应用不同的映射规则。
每个模板都有一个名称,用来描述这个模板的用途, 一个 mapping 来指定映射应该怎样使用,以及至少一个参数 (如 match) 来定义这个模板适用于哪个字段。
例如,上一节我们创建people索引时,JSON的整型被Elasticsearch映射成了long类型,相比于integer类型,long类型会占用更多的磁盘空间。我们想让Elasticsearch将整型映射成integer:
PUT /dynamic_template_test
{
"mappings": {
"dynamic_templates": [
{
"integers": { # to be deleted。 每个模板都有一个名称,用来描述这个模板的用途
"match_mapping_type": "long", # to be deleted。一个参数 (如match) 来定义这个模板适用于哪个字段
"mapping": { # to be deleted。 一个mapping来指定映射应该怎样使用
"type": "integer"
}
}
}
]
}
}
此时往dynamic_template_test中插入一条文档,再获取它的mapping:

和上一节的行为不同,此时in_stock被映射成为integer类型。
当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2014-01-01 。如果它像日期,这个字段就会被作为 date 类型添加。否则,它会被作为 string 类型添加。
有些时候这个行为可能导致一些问题。想象下,你有如下这样的一个文档:
{ "note": "2014-01-01" }
假设这是第一次识别 note 字段,它会被添加为 date 字段。但是如果下一个文档像这样:
{ "note": "Logged out" }
这显然不是一个日期,但为时已晚。这个字段已经是一个日期类型,这个 不合法的日期 将会造成一个异常。
日期检测可以通过在根对象上设置 date_detection 为 false 来关闭:
PUT /my_index
{
"mappings": {
"my_type": {
"date_detection": false
}
}
}
使用这个映射,字符串将始终作为 string 类型。如果你需要一个 date 字段,你必须手动添加。
默认dynamic template里的规则字义对所有满足条件的field都应用,我们也可以使用match和unmatch参数来进行匹配。match用于匹配场景,当匹配成功时,unmatch用于过滤掉某些场景。
上面的文字有点绕,我们以实际案例来说明。在上一节,我们了解到Elasticsearch的动态映射默认会将字符串同时映射为text和keyword,这样要创建两份索引会占用额外的磁盘空间;我们想实现这样一种效果:
text_*开头时,将其映射为text;且忽略text_*_keyword这种情况*_keyword结尾时,将其映射为keyword类型此时的dynamic template声明为:
PUT /test_index
{
"mappings": {
"dynamic_templates": [
{
"strings_only_text": {
"match_mapping_type": "string",
"match": "text_*",
"unmatch": "*_keyword",
"mapping": {
"type": "text"
}
}
},
{
"strings_only_keyword": {
"match_mapping_type": "string",
"match": "*_keyword",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
插入一条测试文档:
POST /test_index/_doc
{
"text_product_description": "A description",
"text_product_id_keyword": "ABC-123"
}
然后获取它的mapping:

和预想一致:
text_product_description以text_开头,且不以_keyword结尾,被映射成text类型;text_product_id_keyword以_keyword结尾,被映射成keyword类型模板按照顺序来检测;第一个匹配的模板会被启用。例如,我们给 string 类型字段定义两个模板:
es :以 _es 结尾的字段名需要使用 spanish 分词器。en :所有其他字段使用 english 分词器。我们将 es 模板放在第一位,因为它比匹配所有字符串字段的 en 模板更特殊:
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic_templates": [
{ "es": {
"match": "*_es",
"match_mapping_type": "string",
"mapping": {
"type": "string",
"analyzer": "spanish"
}
}},
{ "en": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "string",
"analyzer": "english"
}
}}
]
}}}
上面的match和unmatch可以使用星号*做名称匹配,而match_pattern则支持正则表达式:

path_match用于匹配嵌套对象类型。
path_match 参数匹配字段在对象上的完整路径,所以 address.*.name 将匹配这样的字段:
{
"address": {
"city": {
"name": "New York"
}
}
}
例如:

在上一章最后,我们也介绍过index template,它在创建新index时可以自动应用提前设定的 settings 和 mappings。
它的Dynamic template的区别是:
Index template的规则作用于索引名称级别,它匹配的是特定的索引名称,如access-log-*
Dynamic template的规则作用于字段级别,它匹配的是满足特定条件的field。