[[dynamic-templates]] === Dynamic templates Dynamic templates allow you to define custom mappings that can be applied to dynamically added fields based on: * the <> detected by Elasticsearch, with <>. * the name of the field, with <> or <>. * the full dotted path to the field, with <>. The original field name `{name}` and the detected datatype `{dynamic_type`} <> can be used in the mapping specification as placeholders. IMPORTANT: Dynamic field mappings are only added when a field contains a concrete value -- not `null` or an empty array. This means that if the `null_value` option is used in a `dynamic_template`, it will only be applied after the first document with a concrete value for the field has been indexed. Dynamic templates are specified as an array of named objects: [source,js] -------------------------------------------------- "dynamic_templates": [ { "my_template_name": { <1> ... match conditions ... <2> "mapping": { ... } <3> } }, ... ] -------------------------------------------------- <1> The template name can be any string value. <2> The match conditions can include any of : `match_mapping_type`, `match`, `match_pattern`, `unmatch`, `match_path`, `unmatch_path`. <3> The mapping that the matched field should use. Templates are processed in order -- the first matching template wins. New templates can be appended to the end of the list with the <> API. If a new template has the same name as an existing template, it will replace the old version. [[match-mapping-type]] ==== `match_mapping_type` The `match_mapping_type` matches on the datatype detected by <>, in other words, the datatype that Elasticsearch thinks the field should have. Only the following datatypes can be automatically detected: `boolean`, `date`, `double`, `long`, `object`, `string`. It also accepts `*` to match all datatypes. For example, if we wanted to map all integer fields as `integer` instead of `long`, and all `string` fields as both `analyzed` and `not_analyzed`, we could use the following template: [source,js] -------------------------------------------------- PUT my_index { "mappings": { "my_type": { "dynamic_templates": [ { "integers": { "match_mapping_type": "long", "mapping": { "type": "integer" } } }, { "strings": { "match_mapping_type": "string", "mapping": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed", "ignore_above": 256 } } } } } ] } } } PUT my_index/my_type/1 { "my_integer": 5, <1> "my_string": "Some string" <2> } -------------------------------------------------- // AUTOSENSE <1> The `my_integer` field is mapped as an `integer`. <2> The `my_string` field is mapped as an analyzed `string`, with a `not_analyzed` <>. [[match-unmatch]] ==== `match` and `unmatch` The `match` parameter uses a pattern to match on the fieldname, while `unmatch` uses a pattern to exclude fields matched by `match`. The following example matches all `string` fields whose name starts with `long_` (except for those which end with `_text`) and maps them as `long` fields: [source,js] -------------------------------------------------- PUT my_index { "mappings": { "my_type": { "dynamic_templates": [ { "longs_as_strings": { "match_mapping_type": "string", "match": "long_*", "unmatch": "*_text", "mapping": { "type": "long" } } } ] } } } PUT my_index/my_type/1 { "long_num": "5", <1> "long_text": "foo" <2> } -------------------------------------------------- // AUTOSENSE <1> The `long_num` field is mapped as a `long`. <2> The `long_text` field uses the default `string` mapping. [[match-pattern]] ==== `match_pattern` The `match_pattern` parameter behaves just like the `match` parameter, but supports full Java regular expression matching on the field name instead of simple wildcards, for instance: [source,js] -------------------------------------------------- "match_pattern": "^profit_\d+$" -------------------------------------------------- [[path-match-unmatch]] ==== `path_match` and `path_unmatch` The `path_match` and `path_unmatch` parameters work in the same way as `match` and `unmatch`, but operate on the full dotted path to the field, not just the final name, e.g. `some_object.*.some_field`. This example copies the values of any fields in the `name` object to the top-level `full_name` field, except for the `middle` field: [source,js] -------------------------------------------------- PUT my_index { "mappings": { "my_type": { "dynamic_templates": [ { "full_name": { "path_match": "name.*", "path_unmatch": "*.middle", "mapping": { "type": "string", "copy_to": "full_name" } } } ] } } } PUT my_index/my_type/1 { "name": { "first": "Alice", "middle": "Mary", "last": "White" } } -------------------------------------------------- // AUTOSENSE [[template-variables]] ==== `{name}` and `{dynamic_type}` The `{name}` and `{dynamic_type}` placeholders are replaced in the `mapping` with the field name and detected dynamic type. The following example sets all string fields to use an <> with the same name as the field, and disables <> for all non-string fields: [source,js] -------------------------------------------------- PUT my_index { "mappings": { "my_type": { "dynamic_templates": [ { "named_analyzers": { "match_mapping_type": "string", "match": "*", "mapping": { "type": "string", "analyzer": "{name}" } } }, { "no_doc_values": { "match_mapping_type":"*", "mapping": { "type": "{dynamic_type}", "doc_values": false } } } ] } } } PUT my_index/my_type/1 { "english": "Some English text", <1> "count": 5 <2> } -------------------------------------------------- // AUTOSENSE <1> The `english` field is mapped as a `string` field with the `english` analyzer. <2> The `count` field is mapped as a `long` field with `doc_values` disabled