Skip to content

Commit 5c99692

Browse files
authored
Allow specify dynamic templates in bulk request (#69948)
This change allows users to specify dynamic templates in a bulk request. ``` PUT myindex { "mappings": { "dynamic_templates": [{ "time_histograms": { "mapping": { "type": "histogram", "meta": { "unit": "s" } } } }] } } ``` ``` POST myindex/_bulk { "index": { "dynamic_templates": { "response_times": "time_histograms" } } } { "@timestamp": "2020-08-12", "response_times": { "values": [1, 10], "counts": [5, 1] }} ``` Closes #61939
1 parent de228ee commit 5c99692

File tree

28 files changed

+921
-98
lines changed

28 files changed

+921
-98
lines changed

docs/reference/docs/bulk.asciidoc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-index]
283283
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-id]
284284

285285
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-require-alias]
286+
287+
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-dynamic-templates]
286288
--
287289

288290
`delete`::
@@ -311,6 +313,8 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-index]
311313
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-id]
312314

313315
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-require-alias]
316+
317+
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=bulk-dynamic-templates]
314318
--
315319

316320
`update`::
@@ -738,3 +742,39 @@ The API returns the following result.
738742
}
739743
----
740744
// TESTRESPONSE[s/"index_uuid": "aAsFqTI0Tc2W0LCWgPNrOA"/"index_uuid": $body.$_path/]
745+
746+
747+
[discrete]
748+
[[bulk-dynamic-templates]]
749+
===== Example with dynamic templates parameter
750+
751+
The below example creates a dynamic template, then performs a bulk request
752+
consisting of index/create requests with the `dynamic_templates` parameter.
753+
754+
[source,console]
755+
----
756+
PUT my-index/
757+
{
758+
"mappings": {
759+
"dynamic_templates": [
760+
{
761+
"geo_point": {
762+
"mapping": {
763+
"type" : "geo_point"
764+
}
765+
}
766+
}
767+
]
768+
}
769+
}
770+
771+
POST /_bulk
772+
{ "index" : { "_index" : "my_index", "_id" : "1", "dynamic_templates": {"work_location": "geo_point"}} }
773+
{ "field" : "value1", "work_location": "41.12,-71.34", "raw_location": "41.12,-71.34"}
774+
{ "create" : { "_index" : "my_index", "_id" : "2", "dynamic_templates": {"home_location": "geo_point"}} }
775+
{ "field" : "value2", "home_location": "41.12,-71.34"}
776+
----
777+
778+
The bulk request creates two new fields `work_location` and `home_location` with type `geo_point` according
779+
to the `dynamic_templates` parameter; however, the `raw_location` field is created using default dynamic mapping
780+
rules, as a `text` field in that case since it is supplied as a string in the JSON document.

docs/reference/mapping/dynamic/templates.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ name
1414
* <<path-match-unmatch,`path_match` and `path_unmatch`>> operate on the full
1515
dotted path to the field
1616

17+
* if a dynamic template does not define `match_mapping_type` nor `match` nor
18+
`path_match`, then it won't match any field, but it can be referred to by
19+
name in `dynamic_templates` as part of a <bulk, bulk request>.
20+
1721
Use the `{name}` and `{dynamic_type}` <<template-variables,template variables>>
1822
in the mapping specification as placeholders.
1923

docs/reference/rest-api/common-parms.asciidoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,15 @@ If `true`, the destination must be an <<indices-aliases,index alias>>. Defaults
626626
`false`.
627627
end::require-alias[]
628628

629+
tag::bulk-dynamic-templates[]
630+
`dynamic_templates`::
631+
(Optional, map)
632+
A map from the full name of fields to the name of <<dynamic-templates, dynamic templates>.
633+
Defaults to an empty map. If a name matches a dynamic template, then that template will be
634+
applied regardless of other match predicates defined in the template. And if a field is
635+
already defined in the mapping, then this parameter won't be used.
636+
end::bulk-dynamic-templates[]
637+
629638
tag::node-filter[]
630639
`<node_filter>`::
631640
(Optional, string)
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
"Dynamic templates":
3+
- skip:
4+
version: " - 7.99.99"
5+
reason: "Dynamic templates parameter is added to bulk requests in 8.0"
6+
7+
- do:
8+
indices.create:
9+
index: test_index
10+
body:
11+
mappings:
12+
dynamic_templates:
13+
- location:
14+
mapping:
15+
type: geo_point
16+
- my_location:
17+
match: my*
18+
mapping:
19+
type: geo_point
20+
- string:
21+
mapping:
22+
type: keyword
23+
- do:
24+
bulk:
25+
refresh: true
26+
body:
27+
- index:
28+
_index: test_index
29+
_id: id_1
30+
dynamic_templates:
31+
location: location
32+
- { "location": [ -71.34, 41.12 ]}
33+
- index:
34+
_index: test_index
35+
_id: id_2
36+
dynamic_templates:
37+
location: location
38+
- { "location": "41.12,-71.34"}
39+
- match: { errors: false }
40+
- match: { items.0.index.result: created }
41+
- match: { items.1.index.result: created }
42+
43+
- do:
44+
search:
45+
index: test_index
46+
body:
47+
query:
48+
geo_bounding_box:
49+
location:
50+
top_left:
51+
lat: 42
52+
lon: -72
53+
bottom_right:
54+
lat: 40
55+
lon: -74
56+
- match: { hits.total.value: 2 }
57+
- match: { hits.hits.0._id: id_1 }
58+
- match: { hits.hits.1._id: id_2 }
59+
60+
- do:
61+
bulk:
62+
refresh: true
63+
body:
64+
- index:
65+
_index: test_index
66+
_id: id_3
67+
- { "my_location": "41.12,-71.34" } # matches the field name defined in the `my_location` template
68+
- index:
69+
_index: test_index
70+
_id: id_4
71+
dynamic_templates:
72+
my_location: my_location
73+
- { "my_location": "41.12,-71.34" } # use dynamic_templates parameter
74+
- do:
75+
search:
76+
index: test_index
77+
body:
78+
query:
79+
geo_bounding_box:
80+
my_location:
81+
top_left:
82+
lat: 42
83+
lon: -72
84+
bottom_right:
85+
lat: 40
86+
lon: -74
87+
- match: { hits.total.value: 2 }
88+
- match: { hits.hits.0._id: id_3 }
89+
- match: { hits.hits.1._id: id_4 }
90+
91+
- do:
92+
bulk:
93+
refresh: true
94+
body:
95+
- index:
96+
_index: test_index
97+
_id: id_5
98+
dynamic_templates:
99+
location: foo_bar # ok as fields are defined
100+
- { "location": [ -71.34, 41.12 ]}
101+
- index:
102+
_index: test_index
103+
_id: id_6
104+
dynamic_templates:
105+
my_location: foo_bar # ok as fields are defined
106+
- { "my_location": "41.12,-71.34" }
107+
- index:
108+
_index: test_index
109+
_id: id_7
110+
dynamic_templates:
111+
location: bar_foo # ok as fields are defined
112+
- { "location": "41.12,-71.34" }
113+
- match: { errors: false }
114+
- match: { items.0.index.result: created }
115+
- match: { items.1.index.result: created }
116+
- match: { items.2.index.result: created }
117+
118+
- do:
119+
bulk:
120+
refresh: true
121+
body:
122+
- index:
123+
_index: test_index
124+
_id: id_8
125+
dynamic_templates:
126+
foo_location: bar_foo
127+
- { "foo_location": [ -71.34, 41.12 ] } # failed because dynamic template is not found
128+
- index:
129+
_index: test_index
130+
_id: id_9
131+
dynamic_templates:
132+
foo_location: foo_bar
133+
- { "foo_location": "41.12,-71.34" } # failed because dynamic template is not found
134+
- index:
135+
_index: test_index
136+
_id: id_10
137+
dynamic_templates:
138+
new_location: foo
139+
- { "location": "41.12,-71.34"} # ok as fields are defined
140+
- match: { errors: true }
141+
- match: { items.0.index.status: 400 }
142+
- match: { items.0.index.error.type: mapper_parsing_exception }
143+
- match: { items.0.index.error.reason: "Can't find dynamic template for dynamic template name [bar_foo] of field [foo_location]"}
144+
- match: { items.1.index.status: 400 }
145+
- match: { items.1.index.error.type: mapper_parsing_exception }
146+
- match: { items.1.index.error.reason: "Can't find dynamic template for dynamic template name [foo_bar] of field [foo_location]"}
147+
- match: { items.2.index.status: 201 }
148+
- match: { items.2.index.result: created }
149+
150+
# Dynamic template has a wrong type
151+
- do:
152+
bulk:
153+
body:
154+
- index:
155+
_index: test_index
156+
_id: id_11
157+
dynamic_templates:
158+
foo: string
159+
- { "foo.bar": "hello world" } # failed because dynamic template has a wrong type
160+
- index:
161+
_index: test_index
162+
_id: id_12
163+
dynamic_templates:
164+
foo.bar: string
165+
- { "foo.bar": "hello world" } # ok
166+
- match: { errors: true }
167+
- match: { items.0.index.status: 400 }
168+
- match: { items.0.index.error.type: mapper_parsing_exception }
169+
- match: { items.0.index.error.reason: "Field [foo] must be an object; but it's configured as [keyword] in dynamic template [string]"}
170+
- match: { items.1.index.status: 201 }
171+
- match: { items.1.index.result: created }

0 commit comments

Comments
 (0)