加载中

动态模板

动态模板允许您更好地控制 Elasticsearch 映射数据的方式,超越了默认的动态字段映射规则。您可以通过将 dynamic 参数设置为 trueruntime 来启用动态映射。然后,您可以使用动态模板根据匹配条件为动态添加的字段定义自定义映射。

在映射规范中使用 {{name}}{{dynamic_type}} 模板变量作为占位符。

重要提示

动态字段映射仅在字段包含具体值时添加。当字段包含 null 或空数组时,Elasticsearch 不会添加动态字段映射。如果在 dynamic_template 中使用了 null_value 选项,它仅在第一个具有该字段具体值的文档被索引后才会应用。

动态模板被指定为命名对象的数组。

"dynamic_templates": [
  {
    "my_template_name": {
      ... match conditions ...
      "mapping": { ... }
    }
  },
  ...
]
		
  1. 模板名称可以是任何字符串值。
  2. 匹配条件可以包含以下任意项:match_mapping_typematchmatch_patternunmatchpath_matchpath_unmatch
  3. 匹配字段应使用的映射。

如果提供的映射包含无效的映射片段,则会返回验证错误。验证发生在索引时应用动态模板时,并且在大多数情况下,在更新动态模板时也会发生验证。提供无效的映射片段可能会导致在某些条件下更新或验证动态模板失败。

  • 如果没有指定 match_mapping_type 但该模板对于至少一种预定义映射类型有效,则该映射片段被视为有效。但是,如果匹配该模板的字段被索引为不同类型,则在索引时会返回验证错误。例如,配置一个没有 match_mapping_type 的动态模板被视为字符串类型是有效的,但如果匹配该动态模板的字段被索引为长整型(long),则在索引时会返回验证错误。建议将 match_mapping_type 配置为预期的 JSON 类型,或在映射片段中配置所需的 type
  • 如果在映射片段中使用了 {{name}} 占位符,则在更新动态模板时会跳过验证。这是因为此时字段名称未知。相反,验证会在索引时应用模板时进行。

模板按顺序处理——第一个匹配的模板胜出。当通过 更新映射 API 放入新的动态模板时,所有现有模板都会被覆盖。这允许在最初添加动态模板后对其进行重新排序或删除。

如果您希望 Elasticsearch 将特定类型的新字段动态映射为运行时字段,请在索引映射中设置 "dynamic":"runtime"。这些字段不会被索引,而是在查询时从 _source 加载。

或者,您可以使用默认的动态映射规则,然后创建动态模板将特定字段映射为运行时字段。您在索引映射中设置 "dynamic":"true",然后创建一个动态模板,将特定类型的新字段映射为运行时字段。

假设您的数据中每个字段都以 ip_ 开头。基于动态映射规则,Elasticsearch 会将通过 numeric 检测的任何 string 映射为 floatlong。但是,您可以创建一个动态模板,将新字符串映射为 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 参数根据 JSON 解析器检测到的数据类型匹配字段,而 unmatch_mapping_type 则根据数据类型排除字段。

由于 JSON 不区分 longinteger,也不区分 doublefloat,因此任何解析出的浮点数都被视为 double JSON 数据类型,而任何解析出的 integer 数字都被视为 long

注意

使用动态映射时,Elasticsearch 总是会选择较宽的数据类型。唯一的例外是 float,它比 double 需要的存储空间更少,并且对于大多数应用来说精度足够。运行时字段不支持 float,这就是为什么 "dynamic":"runtime" 使用 double 的原因。

Elasticsearch 自动检测以下数据类型

Elasticsearch 数据类型
JSON 数据类型 "dynamic":"true" "dynamic":"runtime"
null 未添加字段 未添加字段
truefalse boolean boolean
double float double
long long long
object object 未添加字段
数组 取决于数组中的第一个非 null 取决于数组中的第一个非 null
通过 日期检测string date date
通过 数值检测string floatlong doublelong
未通过 date 检测或 numeric 检测的 string 带有 .keyword 子字段的 text keyword

您可以为 match_mapping_typeunmatch_mapping_type 参数指定单个数据类型或数据类型列表。您还可以对 match_mapping_type 参数使用通配符 (*) 来匹配所有数据类型。

例如,如果我们想将所有整数类型的字段映射为 integer 而不是 long,并将所有 string 类型的字段同时映射为 textkeyword,我们可以使用以下模板

				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}
}
		
  1. my_integer 字段被映射为 integer
  2. my_string 字段被映射为 text,并带有 keyword 多字段
  3. my_boolean 字段被映射为 keyword
  4. field.count 字段被映射为 long

match 参数使用一个或多个模式来匹配字段名称,而 unmatch 使用一个或多个模式来排除被 match 匹配的字段。

match_pattern 参数调整 match 参数的行为,以支持在字段名称上匹配完整的 Java 正则表达式,而不是简单的通配符。例如

"match_pattern": "regex",
"match": "^profit_\d+$"
		

以下示例匹配所有名称以 long_ 开头的 string 字段(以 _text 结尾的字段除外),并将它们映射为 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"
}
		
  1. long_num 字段被映射为 long
  2. long_text 字段使用默认的 string 映射。

您可以为 matchunmatch 字段指定一个使用 JSON 数组的模式列表。

下一个示例匹配所有名称以 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-000001/_doc/1
					{
  "one_ip":   "will not match",
  "ip_two":   "will not match",
  "three_ip": "12.12.12.12",
  "ip_four":  "13.13.13.13"
}
		
  1. one_ip 字段未匹配,因此使用 text 的默认映射。
  2. ip_two 字段未匹配,因此使用 text 的默认映射。
  3. three_ip 字段被映射为 ip 类型。
  4. ip_four 字段被映射为 ip 类型。

path_matchpath_unmatch 参数的工作方式与 matchunmatch 相同,但它们对字段的完整点分路径(例如 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_matchpath_unmatch 都使用了模式数组。

name 对象或 user.name 对象中任何字段的值都会被复制到顶层 full_name 字段,但 middlemidinitial 字段除外

				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_matchpath_unmatch 参数不仅匹配叶子字段,还匹配对象路径。例如,索引以下文档会导致错误,因为 path_match 设置也匹配了对象字段 name.title,它不能被映射为 text

				PUT my-index-000001/_doc/2
					{
  "name": {
    "first":  "Paul",
    "last":   "McCartney",
    "title": {
      "value": "Sir",
      "category": "order of chivalry"
    }
  }
}
		

{{name}}{{dynamic_type}} 占位符会在 mapping 中被替换为字段名称和检测到的动态类型。以下示例将所有字符串字段设置为使用与字段同名的 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
}
		
  1. english 字段被映射为带有 english 分析器的 string 字段。
  2. count 字段被映射为禁用了 doc_valueslong 字段。

以下是一些可能有用的动态模板示例

当您设置 "dynamic":"true" 时,Elasticsearch 会将字符串字段映射为带有 keyword 子字段的 text 字段。如果您只索引结构化内容且对全文搜索不感兴趣,您可以让 Elasticsearch 仅将您的字段映射为 keyword 字段。但是,您必须搜索索引时的完全相同的值才能搜索这些字段。

				PUT my-index-000001
					{
  "mappings": {
    "dynamic_templates": [
      {
        "strings_as_keywords": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "keyword"
          }
        }
      }
    ]
  }
}
		

与前面的示例相反,如果您只关心字符串字段的全文搜索,并且不打算进行聚合、排序或精确搜索,您可以指示 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"
        }
      }
    }
  }
}
		

Norms 是索引时的评分因子。如果您不关心评分(例如,如果您从不按分数对文档进行排序),您可以禁用这些评分因子在索引中的存储,从而节省一些空间。

				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 字段是为了与动态映射的默认规则保持一致。当然,如果您不需要它们,因为您不需要对该字段执行精确搜索或聚合,您可以按照上一节所述将其删除。

在使用 Elasticsearch 进行时间序列分析时,通常会有许多数字字段,您经常会对这些字段进行聚合,但从不进行过滤。在这种情况下,您可以禁用这些字段上的索引以节省磁盘空间,并可能获得一些索引速度的提升

				PUT my-index-000001
					{
  "mappings": {
    "dynamic_templates": [
      {
        "unindexed_longs": {
          "match_mapping_type": "long",
          "mapping": {
            "type": "long",
            "index": false
          }
        }
      },
      {
        "unindexed_doubles": {
          "match_mapping_type": "double",
          "mapping": {
            "type": "float",
            "index": false
          }
        }
      }
    ]
  }
}
		
  1. 与默认的动态映射规则一样,double 被映射为 float,这通常足够精确,但需要的磁盘空间只有前者的一半。
© . This website operates independently and is not affiliated with or endorsed by Elasticsearch B.V. All brand names, logos, and trademarks are the property of their respective owners.