一、动态映射介绍
在关系型数据库中,得先创建表,指定字段和字段类型,才能将数据插入表中。在ES中,索引就相当于表,文档就相当于记录,文档里面的字段就相当于表的字段,字段同样有数据类型。mapping就用来定义文档有哪些字段,这些字段如何存储和索引。
Elasticsearch 与关系型数据库不同之处在于,其不需要先定义表结构,而可以根据写入文档的内容,来推断字段和数据类型,创建索引结构,这就是dynamic mapping,动态映射的由来。这提供了极大的灵活性。 另外需要注意的是,一个索引的字段数量有上限的,超过上限就会报错。
当 Elasticsearch 遇到文档中以前未遇到的字段,它用dynamic mapping来确定字段的数据类型并自动把新的字段添加到类型映射。
有时这是想要的行为有时又不希望这样。通常没有人知道以后会有什么新字段加到文档,但是又希望这些字段被自动的索引。也许你只想忽略它们。如果Elasticsearch是作为重要的数据存储,可能就会期望遇到新字段就会抛出异常,这样能及时发现问题。
幸运的是可以用 dynamic
配置来控制这种行为 ,可接受的选项如下:
动态模式(dynamic:true):动态添加新的字段(默认),根据输入文档的内容,自动推断字段和类型,创建mapping。
非动态模式(dynamic:false):忽略新的字段,无法根据输入文档的内容,自动创建mapping,需要手动创建mapping。
严格模式(dynamic:strict):如果遇到新字段抛出异常,同非动态模式,区别在于,非动态模式,输入的文档中如果有字段不在mapping中,依然可以存储和读取,但是该字段不在mapping中,因此也无法根据该字段进行检索;但严格模式,无法存储,会直接报错,严格模式实际上就类似于关系型数据库中的表了。
配置参数 dynamic
可以用在根 object
或任何 object
类型的字段上。你可以将 dynamic
的默认值设置为 strict
, 而只在指定的内部对象中开启它,例如:
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict",
"properties": {
"title": { "type": "string"},
"stash": {
"type": "object",
"dynamic": true
}
}
}
}
}
使用上述动态映射, 你可以给 stash
对象添加新的可检索的字段:
PUT /my_index/my_type/1
{
"title": "This doc adds a new field",
"stash": { "new_field": "Success!" }
}
但是对根节点对象 my_type
进行同样的操作会失败:
PUT /my_index/my_type/1
{
"title": "This throws a StrictDynamicMappingException",
"new_field": "Fail!"
}
二、自定义动态映射
如果你想在运行时增加新的字段,你可能会启用动态映射。然而,有时候,动态映射 规则
可能不太智能。幸运的是,我们可以通过设置去自定义这些规则,以便更好的适用于你的数据。
2.1 日期检测
当 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
字段,你必须手动添加。
2.2 动态模板
使用 dynamic_templates
,你可以完全控制新检测生成字段的映射。你甚至可以通过字段名称或数据类型来应用不同的映射。
每个模板都有一个名称,你可以用来描述这个模板的用途, 一个 mapping
来指定映射应该怎样使用,以及至少一个参数 (如 match
) 来定义这个模板适用于哪个字段。
模板按照顺序来检测;第一个匹配的模板会被启用。例如,我们给 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
允许你应用模板到特定类型的字段上,就像有标准动态映射规则检测的一样, (例如 string
或 long
)。
match
参数只匹配字段名称, path_match
参数匹配字段在对象上的完整路径,所以 address.*.name
将匹配这样的字段:
{
"address": {
"city": {
"name": "New York"
}
}
}
unmatch
和 path_unmatch
将被用于未被匹配的字段。
三、缺省映射
通常,一个索引中的所有类型共享相同的字段和设置。 _default_
映射更加方便地指定通用设置,而不是每次创建新类型时都要重复设置。 _default_
映射是新类型的模板。在设置 _default_
映射之后创建的所有类型都将应用这些缺省的设置,除非类型在自己的映射中明确覆盖这些设置。
例如,我们可以使用 _default_
映射为所有的类型禁用 _all
字段, 而只在 blog
类型启用:
PUT /my_index
{
"mappings": {
"_default_": {
"_all": { "enabled": false }
},
"blog": {
"_all": { "enabled": true }
}
}
}
_default_
映射也是一个指定索引dynamic templates的好方法。
资料来源: