动态映射
edit动态映射
editElasticsearch 最重要的特性之一是它试图尽量减少你的操作,让你能够尽快开始探索你的数据。要索引一个文档,你不需要先创建索引、定义映射类型和定义字段——你只需索引一个文档,索引、类型和字段将自动显示:
自动检测和添加新字段称为动态映射。可以通过自定义动态映射规则来适应您的需求,使用:
- Dynamic field mappings
- 动态字段检测的规则。
- Dynamic templates
- 自定义规则以配置动态添加字段的映射。
索引模板允许您配置新索引的默认映射、设置和别名,无论是自动创建还是显式创建。
动态字段映射
edit当Elasticsearch检测到文档中的新字段时,默认情况下它会动态地将该字段添加到类型映射中。dynamic参数控制此行为。
您可以明确指示 Elasticsearch 根据传入的文档动态创建字段,方法是将 dynamic 参数设置为 true 或 runtime。当启用动态字段映射时,Elasticsearch 使用下表中的规则来确定如何为每个字段映射数据类型。
下表中的字段数据类型是 Elasticsearch 能够动态检测到的唯一字段数据类型。您必须显式映射所有其他数据类型。
Elasticsearch 数据类型 |
||
JSON 数据类型 |
|
|
|
未添加字段 |
未添加字段 |
|
|
|
|
|
|
|
|
|
|
|
未添加字段 |
|
取决于数组中第一个非 |
取决于数组中第一个非 |
|
|
|
|
|
|
|
|
|
您可以禁用动态映射,无论是在文档级别还是在
object 级别。将 dynamic 参数设置为
false 会忽略新字段,而 strict 会在 Elasticsearch 遇到未知字段时拒绝文档。
使用更新映射 API 来更新现有字段上的 dynamic 设置。
您可以自定义动态字段映射规则,用于
日期检测 和 数值检测。
要定义可应用于其他动态字段的定制映射规则,请使用 dynamic_templates。
日期检测
edit如果启用了 date_detection(默认),那么新字符串字段将被检查,以查看其内容是否与 dynamic_date_formats 中指定的任何日期模式匹配。如果找到匹配项,则会添加一个具有相应格式的新 date 字段。
默认值为 dynamic_date_formats:
[ "严格日期可选时间","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
例如:
|
已添加 |
禁用日期检测
edit动态日期检测可以通过将 date_detection 设置为 false 来禁用:
PUT my-index-000001
{
"mappings": {
"date_detection": false
}
}
PUT my-index-000001/_doc/1
{
"create_date": "2015/09/02"
}
|
已添加 |
自定义检测到的日期格式
edit或者,可以自定义 dynamic_date_formats 以支持您自己的 日期格式:
PUT my-index-000001
{
"mappings": {
"dynamic_date_formats": ["MM/dd/yyyy"]
}
}
PUT my-index-000001/_doc/1
{
"create_date": "09/25/2015"
}
在配置日期模式数组和在单个字符串中配置由||分隔的多个模式之间存在差异。当你配置日期模式数组时,第一个文档中未映射日期字段的匹配模式将决定该字段的映射:
PUT my-index-000001
{
"mappings": {
"dynamic_date_formats": [ "yyyy/MM", "MM/dd/yyyy"]
}
}
PUT my-index-000001/_doc/1
{
"create_date": "09/25/2015"
}
生成的映射将是:
{
"my-index-000001": {
"mappings": {
"dynamic_date_formats": [
"yyyy/MM",
"MM/dd/yyyy"
],
"properties": {
"create_date": {
"type": "date",
"format": "MM/dd/yyyy"
}
}
}
}
}
在单个字符串中配置多个用 || 分隔的模式,会生成一个支持任何日期格式的映射。这使您能够索引使用不同格式的文档:
PUT my-index-000001
{
"mappings": {
"dynamic_date_formats": [ "yyyy/MM||MM/dd/yyyy"]
}
}
PUT my-index-000001/_doc/1
{
"create_date": "09/25/2015"
}
生成的映射将是:
{
"my-index-000001": {
"mappings": {
"dynamic_date_formats": [
"yyyy/MM||MM/dd/yyyy"
],
"properties": {
"create_date": {
"type": "date",
"format": "yyyy/MM||MM/dd/yyyy"
}
}
}
}
}
时间戳格式(epoch_millis 和 epoch_second)不支持作为动态日期格式。
动态模板
edit动态模板允许您对Elasticsearch如何映射您的数据进行更大的控制,超越默认的动态字段映射规则。您可以通过将动态参数设置为true或runtime来启用动态映射。然后,您可以使用动态模板定义自定义映射,这些映射可以根据匹配条件应用于动态添加的字段:
-
match_mapping_type和unmatch_mapping_type操作 Elasticsearch 检测到的数据类型 -
match和unmatch使用模式匹配字段名称 -
path_match和path_unmatch操作字段的完整点路径 -
如果动态模板没有定义
match_mapping_type、match或path_match,它将不会匹配任何字段。您仍然可以在 批量请求 的dynamic_templates部分中按名称引用该模板。
在映射规范中使用 {name} 和 {dynamic_type} 模板变量 作为占位符。
动态字段映射仅在字段包含具体值时才会添加。当字段包含null或空数组时,Elasticsearch不会添加动态字段映射。如果在dynamic_template中使用了null_value选项,它仅在包含该字段具体值的第一个文档被索引后才会应用。
动态模板被指定为一个命名对象的数组:
"dynamic_templates": [
{
"my_template_name": {
... match conditions ...
"mapping": { ... }
}
},
...
]
|
模板名称可以是任何字符串值。 |
|
|
匹配条件可以包括以下任意一项: |
|
|
匹配字段应使用的映射。 |
验证动态模板
edit如果提供的映射包含无效的映射片段,则会返回验证错误。验证发生在索引时应用动态模板时,并且在大多数情况下,当动态模板更新时。在某些条件下,提供无效的映射片段可能会导致动态模板的更新或验证失败:
-
如果没有指定
match_mapping_type,但模板至少对一种预定义的映射类型有效,则映射片段被认为是有效的。然而,如果在索引时有一个匹配模板的字段被索引为不同类型,则会返回验证错误。例如,配置一个没有match_mapping_type的动态模板被认为是有效的字符串类型,但如果一个匹配动态模板的字段被索引为长整型,则在索引时会返回验证错误。建议将match_mapping_type配置为预期的JSON类型,或在映射片段中配置所需的type。 -
如果在映射片段中使用了
{name}占位符,则在更新动态模板时会跳过验证。这是因为此时字段名称是未知的。相反,验证发生在模板在索引时应用的时候。
模板按顺序处理——第一个匹配的模板获胜。当通过更新映射 API 添加新的动态模板时,所有现有的模板都会被覆盖。这允许在最初添加后重新排序或删除动态模板。
在动态模板中映射运行时字段
edit如果您希望 Elasticsearch 将某些类型的新字段动态映射为运行时字段,请在索引映射中设置 "dynamic":"runtime"。这些字段不会被索引,而是在查询时从 _source 加载。
或者,您可以使用默认的动态映射规则,然后创建动态模板将特定字段映射为运行时字段。您在索引映射中设置"dynamic":"true",然后创建一个动态模板,将特定类型的新字段映射为运行时字段。
假设你有一组数据,其中每个字段都以 ip_ 开头。根据
动态映射规则,Elasticsearch 会将通过
numeric 检测的任何 string 映射为 float 或 long。然而,你可以创建一个动态
模板,将新字符串映射为类型为 ip 的运行时字段。
以下请求定义了一个名为 strings_as_ip 的动态模板。当 Elasticsearch 检测到匹配 ip* 模式的新 string 字段时,它会将这些字段映射为类型为 ip 的运行时字段。由于 ip 字段不会动态映射,因此您可以将此模板与 "dynamic":"true" 或 "dynamic":"runtime" 一起使用。
PUT my-index-000001/
{
"mappings": {
"dynamic_templates": [
{
"strings_as_ip": {
"match_mapping_type": "string",
"match": "ip*",
"runtime": {
"type": "ip"
}
}
}
]
}
}
参见此示例,了解如何使用动态模板将string字段映射为索引字段或运行时字段。
match_mapping_type 和 unmatch_mapping_type
edit参数 match_mapping_type 根据 JSON 解析器检测到的数据类型匹配字段,而 unmatch_mapping_type 则根据数据类型排除字段。
因为 JSON 不区分 long 和 integer 或 double 和
float,任何解析的浮点数都被视为 double JSON 数据
类型,而任何解析的 integer 数字都被视为 long。
使用动态映射时,Elasticsearch 总是会选择更宽的数据类型。唯一的例外是 float,它比 double 需要的存储空间更少,并且对于大多数应用程序来说精度已经足够。运行时字段不支持 float,这就是为什么 "dynamic":"runtime" 使用 double。
Elasticsearch 自动检测以下数据类型:
Elasticsearch 数据类型 |
||
JSON 数据类型 |
|
|
|
未添加字段 |
未添加字段 |
|
|
|
|
|
|
|
|
|
|
|
未添加字段 |
|
取决于数组中第一个非 |
取决于数组中第一个非 |
|
|
|
|
|
|
|
|
|
您可以为 match_mapping_type 或 unmatch_mapping_type 参数指定单一数据类型或数据类型列表。您还可以为 match_mapping_type 参数使用通配符 (*) 来匹配所有数据类型。
例如,如果我们想将所有整数字段映射为integer而不是long,并将所有string字段映射为text和keyword,我们可以使用以下模板:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"numeric_counts": {
"match_mapping_type": ["long", "double"],
"match": "count",
"mapping": {
"type": "{dynamic_type}",
"index": false
}
}
},
{
"integers": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
{
"non_objects_keyword": {
"match_mapping_type": "*",
"unmatch_mapping_type": "object",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
PUT my-index-000001/_doc/1
{
"my_integer": 5,
"my_string": "Some string",
"my_boolean": "false",
"field": {"count": 4}
}
|
字段 |
|
|
字段 |
|
|
字段 |
|
|
字段 |
match 和 unmatch
edit参数 match 使用一个或多个模式来匹配字段名称,而 unmatch 使用一个或多个模式来排除由 match 匹配的字段。
参数match_pattern调整了match参数的行为,以支持在字段名称上进行完整的Java正则表达式匹配,而不仅仅是简单的通配符。例如:
"match_pattern": "regex", "match": "^profit_\d+$"
以下示例匹配所有名称以 long_ 开头(但不包括以 _text 结尾的字段)的 string 字段,并将它们映射为 long 字段:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"longs_as_strings": {
"match_mapping_type": "string",
"match": "long_*",
"unmatch": "*_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
PUT my-index-000001/_doc/1
{
"long_num": "5",
"long_text": "foo"
}
您可以使用JSON数组为match或unmatch字段指定一组模式。
下一个示例匹配所有名称以 ip_ 开头或以 _ip 结尾的字段,
但不包括以 one 开头或以 two 结尾的字段,并将它们映射为 ip 字段:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"ip_fields": {
"match": ["ip_*", "*_ip"],
"unmatch": ["one*", "*two"],
"mapping": {
"type": "ip"
}
}
}
]
}
}
PUT my-index/_doc/1
{
"one_ip": "will not match",
"ip_two": "will not match",
"three_ip": "12.12.12.12",
"ip_four": "13.13.13.13"
}
path_match 和 path_unmatch
editThe path_match 和 path_unmatch 参数的工作方式与 match 和 unmatch 相同,但它们作用于字段的全路径,而不仅仅是最终名称,例如 some_object.*.some_field。
此示例将name对象中任何字段的值复制到顶级full_name字段,除了middle字段:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT my-index-000001/_doc/1
{
"name": {
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
以下示例同时使用了 path_match 和 path_unmatch 的模式数组。
在 name 对象或 user.name 对象中的任何字段的值,除了 middle 和 midinitial 字段外,都会被复制到顶层的 full_name 字段中:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"full_name": {
"path_match": ["name.*", "user.name.*"],
"path_unmatch": ["*.middle", "*.midinitial"],
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT my-index-000001/_doc/1
{
"name": {
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
PUT my-index-000001/_doc/2
{
"user": {
"name": {
"first": "Jane",
"midinitial": "M",
"last": "Salazar"
}
}
}
请注意,path_match 和 path_unmatch 参数不仅匹配叶子字段,还匹配对象路径。例如,索引以下文档将导致错误,因为 path_match 设置也匹配对象字段 name.title,而该字段不能映射为文本:
PUT my-index-000001/_doc/2
{
"name": {
"first": "Paul",
"last": "McCartney",
"title": {
"value": "Sir",
"category": "order of chivalry"
}
}
}
模板变量
edit在mapping中,{name}和{dynamic_type}占位符被替换为字段名称和检测到的动态类型。以下示例将所有字符串字段设置为使用与字段名称相同的analyzer,并禁用所有非字符串字段的doc_values:
PUT my-index-000001
{
"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
}
}
}
]
}
}
PUT my-index-000001/_doc/1
{
"english": "Some English text",
"count": 5
}
动态模板示例
edit以下是一些可能有用动态模板的示例:
结构化搜索
edit当你设置"dynamic":"true"时,Elasticsearch会将字符串字段映射为text字段,并带有一个keyword子字段。如果你只索引结构化内容,并且对全文搜索不感兴趣,你可以让Elasticsearch仅将你的字段映射为keyword字段。然而,你必须搜索与索引时完全相同的值才能搜索这些字段。
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
仅文本字符串映射
edit与前面的示例相反,如果您只关心字符串字段上的全文搜索,并且不打算运行聚合、排序或精确搜索,您可以指示 Elasticsearch 将字符串映射为 text:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"strings_as_text": {
"match_mapping_type": "string",
"mapping": {
"type": "text"
}
}
}
]
}
}
或者,您可以创建一个动态模板,将您的字符串字段映射为映射运行时部分中的keyword字段。当Elasticsearch检测到新的string类型字段时,这些字段将被创建为keyword类型的运行时字段。
尽管您的 string 字段不会被索引,但它们的值存储在 _source 中,并且可以在搜索请求、聚合、过滤和排序中使用。
例如,以下请求创建了一个动态模板,将string字段映射为类型为keyword的运行时字段。尽管runtime定义为空,但新的string字段将根据Elasticsearch用于向映射添加字段类型的动态映射规则被映射为keyword运行时字段。任何未通过日期检测或数字检测的string字段都会自动映射为keyword:
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"runtime": {}
}
}
]
}
}
您索引一个简单文档:
PUT my-index-000001/_doc/1
{
"english": "Some English text",
"count": 5
}
当你查看映射时,你会看到english字段是一个类型为keyword的运行时字段:
GET my-index-000001/_mapping
{
"my-index-000001" : {
"mappings" : {
"dynamic_templates" : [
{
"strings_as_keywords" : {
"match_mapping_type" : "string",
"runtime" : { }
}
}
],
"runtime" : {
"english" : {
"type" : "keyword"
}
},
"properties" : {
"count" : {
"type" : "long"
}
}
}
}
}
禁用的规范
edit范数是索引时评分因子。如果你不关心评分,例如如果你从不按分数对文档进行排序,你可以禁用这些评分因子在索引中的存储,从而节省一些空间。
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
}
子字段 keyword 出现在此模板中,以与动态映射的默认规则保持一致。当然,如果您不需要它们,因为您不需要对该字段执行精确搜索或聚合,您可以按照上一节中的描述将其删除。
时间序列
edit在使用 Elasticsearch 进行时间序列分析时,通常会有许多数值字段,这些字段你经常会在聚合操作中使用,但从不进行过滤。在这种情况下,你可以禁用这些字段的索引,以节省磁盘空间,并可能提高索引速度: