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