Skip to content

Commit e3b3bd2

Browse files
authored
Add script parameter to long and double field mappers (#69531) (#71105)
This commit adds a script parameter to long and double fields that makes it possible to calculate a value for these fields at index time. It uses the same script context as the equivalent runtime fields, and allows for multiple index-time scripted fields to cross-refer while still checking for indirection loops.
1 parent d24b0ca commit e3b3bd2

File tree

46 files changed

+1863
-63
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1863
-63
lines changed

benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class ScriptScoreBenchmark {
8181
private final Map<String, MappedFieldType> fieldTypes = org.elasticsearch.common.collect.Map.ofEntries(
8282
org.elasticsearch.common.collect.Map.entry(
8383
"n",
84-
new NumberFieldType("n", NumberType.LONG, false, false, true, true, null, org.elasticsearch.common.collect.Map.of())
84+
new NumberFieldType("n", NumberType.LONG, false, false, true, true, null, org.elasticsearch.common.collect.Map.of(), null)
8585
)
8686
);
8787
private final IndexFieldDataCache fieldDataCache = new IndexFieldDataCache.None();

docs/reference/mapping/types/numeric.asciidoc

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ The following parameters are accepted by numeric types:
117117

118118
Try to convert strings to numbers and truncate fractions for integers.
119119
Accepts `true` (default) and `false`. Not applicable for `unsigned_long`.
120+
Note that this cannot be set if the `script` parameter is used.
120121

121122
<<mapping-boost,`boost`>>::
122123

@@ -132,7 +133,8 @@ The following parameters are accepted by numeric types:
132133
<<ignore-malformed,`ignore_malformed`>>::
133134

134135
If `true`, malformed numbers are ignored. If `false` (default), malformed
135-
numbers throw an exception and reject the whole document.
136+
numbers throw an exception and reject the whole document. Note that this
137+
cannot be set if the `script` parameter is used.
136138

137139
<<mapping-index,`index`>>::
138140

@@ -142,7 +144,26 @@ The following parameters are accepted by numeric types:
142144

143145
Accepts a numeric value of the same `type` as the field which is
144146
substituted for any explicit `null` values. Defaults to `null`, which
145-
means the field is treated as missing.
147+
means the field is treated as missing. Note that this cannot be set
148+
if the `script` parameter is used.
149+
150+
`on_script_error`::
151+
152+
Defines what to do if the script defined by the `script` parameter
153+
throws an error at indexing time. Accepts `reject` (default), which
154+
will cause the entire document to be rejected, and `ignore`, which
155+
will register the field in the document's
156+
<<mapping-ignored-field,`_ignored`>> metadata field and continue
157+
indexing. This parameter can only be set if the `script` field is
158+
also set.
159+
160+
`script`::
161+
162+
If this parameter is set, then the field will index values generated
163+
by this script, rather than reading the values directly from the
164+
source. Scripts are in the same format as their
165+
<<runtime-mapping-fields,runtime equivalent>>. Scripts can only be
166+
configured on `long` and `double` field types.
146167

147168
<<mapping-store,`store`>>::
148169

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/TokenCountFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static class TokenCountFieldType extends NumberFieldMapper.NumberFieldType {
7777

7878
TokenCountFieldType(String name, boolean isSearchable, boolean isStored,
7979
boolean hasDocValues, Number nullValue, Map<String, String> meta) {
80-
super(name, NumberFieldMapper.NumberType.INTEGER, isSearchable, isStored, hasDocValues, false, nullValue, meta);
80+
super(name, NumberFieldMapper.NumberType.INTEGER, isSearchable, isStored, hasDocValues, false, nullValue, meta, null);
8181
}
8282

8383
@Override

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ protected Collection<? extends Plugin> getPlugins() {
5757
return List.of(new MapperExtrasPlugin());
5858
}
5959

60+
@Override
61+
protected boolean allowsStore() {
62+
return false;
63+
}
64+
6065
static int getFrequency(TokenStream tk) throws IOException {
6166
TermFrequencyAttribute freqAttribute = tk.addAttribute(TermFrequencyAttribute.class);
6267
tk.reset();

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapperTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ protected boolean supportsMeta() {
5353
return false;
5454
}
5555

56+
@Override
57+
protected boolean allowsStore() {
58+
return false;
59+
}
60+
5661
public void testDefaults() throws Exception {
5762
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
5863
assertEquals(Strings.toString(fieldMapping(this::minimalMapping)), mapper.mappingSource().toString());
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
setup:
3+
- do:
4+
indices.create:
5+
index: sensor
6+
body:
7+
settings:
8+
number_of_shards: 1
9+
number_of_replicas: 0
10+
mappings:
11+
properties:
12+
timestamp:
13+
type: date
14+
temperature:
15+
type: long
16+
voltage:
17+
type: double
18+
node:
19+
type: keyword
20+
voltage_times_ten:
21+
type: long
22+
script:
23+
source: |
24+
for (double v : doc['voltage']) {
25+
emit((long)(v * params.multiplier));
26+
}
27+
params:
28+
multiplier: 10
29+
voltage_times_ten_no_dv:
30+
type: long
31+
doc_values: false
32+
script:
33+
source: |
34+
for (double v : doc['voltage']) {
35+
emit((long)(v * params.multiplier));
36+
}
37+
params:
38+
multiplier: 10
39+
# test multiple values
40+
temperature_digits:
41+
type: long
42+
script:
43+
source: |
44+
for (long temperature : doc['temperature']) {
45+
long t = temperature;
46+
while (t != 0) {
47+
emit(t % 10);
48+
t /= 10;
49+
}
50+
}
51+
52+
- do:
53+
bulk:
54+
index: sensor
55+
refresh: true
56+
body: |
57+
{"index":{}}
58+
{"timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
59+
{"index":{}}
60+
{"timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
61+
{"index":{}}
62+
{"timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
63+
{"index":{}}
64+
{"timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
65+
{"index":{}}
66+
{"timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
67+
{"index":{}}
68+
{"timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}
69+
70+
---
71+
"get mapping":
72+
- do:
73+
indices.get_mapping:
74+
index: sensor
75+
- match: {sensor.mappings.properties.voltage_times_ten.type: long }
76+
- match:
77+
sensor.mappings.properties.voltage_times_ten.script.source: |
78+
for (double v : doc['voltage']) {
79+
emit((long)(v * params.multiplier));
80+
}
81+
- match: {sensor.mappings.properties.voltage_times_ten.script.params: {multiplier: 10} }
82+
- match: {sensor.mappings.properties.voltage_times_ten.script.lang: painless }
83+
84+
---
85+
"fetch fields":
86+
- do:
87+
search:
88+
index: sensor
89+
body:
90+
sort: timestamp
91+
fields:
92+
- voltage_times_ten
93+
- voltage_times_ten_no_dv
94+
- temperature_digits
95+
- match: {hits.total.value: 6}
96+
- match: {hits.hits.0.fields.voltage_times_ten: [40] }
97+
- match: {hits.hits.0.fields.temperature_digits: [2, 0, 2] }
98+
- match: {hits.hits.0.fields.voltage_times_ten: [40] }
99+
- match: {hits.hits.0.fields.voltage_times_ten_no_dv: [40] }
100+
- match: {hits.hits.1.fields.voltage_times_ten: [42] }
101+
- match: {hits.hits.2.fields.voltage_times_ten: [56] }
102+
- match: {hits.hits.3.fields.voltage_times_ten: [51] }
103+
- match: {hits.hits.4.fields.voltage_times_ten: [58] }
104+
- match: {hits.hits.5.fields.voltage_times_ten: [52] }
105+
106+
---
107+
"docvalue_fields":
108+
- do:
109+
search:
110+
index: sensor
111+
body:
112+
sort: timestamp
113+
docvalue_fields:
114+
- voltage_times_ten
115+
- temperature_digits
116+
- match: {hits.total.value: 6}
117+
- match: {hits.hits.0.fields.voltage_times_ten: [40] }
118+
- match: {hits.hits.0.fields.temperature_digits: [0, 2, 2] }
119+
- match: {hits.hits.0.fields.voltage_times_ten: [40] }
120+
- match: {hits.hits.1.fields.voltage_times_ten: [42] }
121+
- match: {hits.hits.2.fields.voltage_times_ten: [56] }
122+
- match: {hits.hits.3.fields.voltage_times_ten: [51] }
123+
- match: {hits.hits.4.fields.voltage_times_ten: [58] }
124+
- match: {hits.hits.5.fields.voltage_times_ten: [52] }
125+
126+
---
127+
"terms agg":
128+
- do:
129+
search:
130+
index: sensor
131+
body:
132+
aggs:
133+
v10:
134+
terms:
135+
field: voltage_times_ten
136+
- match: {hits.total.value: 6}
137+
- match: {aggregations.v10.buckets.0.key: 40.0}
138+
- match: {aggregations.v10.buckets.0.doc_count: 1}
139+
- match: {aggregations.v10.buckets.1.key: 42.0}
140+
- match: {aggregations.v10.buckets.1.doc_count: 1}
141+
142+
---
143+
"term query":
144+
- do:
145+
search:
146+
index: sensor
147+
body:
148+
query:
149+
term:
150+
voltage_times_ten: 58
151+
- match: {hits.total.value: 1}
152+
- match: {hits.hits.0._source.voltage: 5.8}

0 commit comments

Comments
 (0)