Dynamic template - 动态模板

如果你想在运行时增加新的字段,你可能会启用动态映射。然而,有时候,动态映射的规则可能不太智能。幸运的是,我们可以通过设置去自定义这些规则,以便更好的适用于你的数据。


使用 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:

image-20220724165640675

和上一节的行为不同,此时in_stock被映射成为integer类型。

日期检测

当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2014-01-01 。如果它像日期,这个字段就会被作为 date 类型添加。否则,它会被作为 string 类型添加。

有些时候这个行为可能导致一些问题。想象下,你有如下这样的一个文档:

{ "note": "2014-01-01" }

假设这是第一次识别 note 字段,它会被添加为 date 字段。但是如果下一个文档像这样:

{ "note": "Logged out" }

这显然不是一个日期,但为时已晚。这个字段已经是一个日期类型,这个 不合法的日期 将会造成一个异常。

日期检测可以通过在根对象上设置 date_detectionfalse 来关闭:

PUT /my_index
{
    "mappings": {
        "my_type": {
            "date_detection": false
        }
    }
}

使用这个映射,字符串将始终作为 string 类型。如果你需要一个 date 字段,你必须手动添加。

match和unmatch参数

默认dynamic template里的规则字义对所有满足条件的field都应用,我们也可以使用matchunmatch参数来进行匹配。match用于匹配场景,当匹配成功时,unmatch用于过滤掉某些场景。

上面的文字有点绕,我们以实际案例来说明。在上一节,我们了解到Elasticsearch的动态映射默认会将字符串同时映射为textkeyword,这样要创建两份索引会占用额外的磁盘空间;我们想实现这样一种效果:

  1. 当字段以text_*开头时,将其映射为text;且忽略text_*_keyword这种情况
  2. 当字段以*_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:

image-20220724171232874

和预想一致:

  1. 由于text_product_descriptiontext_开头,且不以_keyword结尾,被映射成text类型;
  2. 由于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_mapping_type参数

上面的match和unmatch可以使用星号*做名称匹配,而match_pattern则支持正则表达式:

image-20220723210829907

path_match

path_match用于匹配嵌套对象类型。

path_match 参数匹配字段在对象上的完整路径,所以 address.*.name 将匹配这样的字段:

{
    "address": {
        "city": {
            "name": "New York"
        }
    }
}

例如:

image-20220723210940866

Index template和dynamic template的区别

在上一章最后,我们也介绍过index template,它在创建新index时可以自动应用提前设定的 settings 和 mappings。

它的Dynamic template的区别是:

  • Index template的规则作用于索引名称级别,它匹配的是特定的索引名称,如access-log-*

  • Dynamic template的规则作用于字段级别,它匹配的是满足特定条件的field。