Skip to content

Commit fe9ee38

Browse files
jdconradastefan
authored andcommitted
Add scaled float to the scripting fields API (elastic#82275)
This adds the mapped type scaled float the scripting fields API using double as the base type.
1 parent f4a1124 commit fe9ee38

File tree

6 files changed

+193
-8
lines changed

6 files changed

+193
-8
lines changed

docs/changelog/82275.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 82275
2+
summary: Add scaled float to the scripting fields API
3+
area: Infra/Scripting
4+
type: enhancement
5+
issues: []

modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class org.elasticsearch.script.field.FloatDocValuesField @dynamic_type {
5656
float get(int, float)
5757
}
5858

59+
class org.elasticsearch.script.field.ScaledFloatDocValuesField @dynamic_type {
60+
double get(double)
61+
double get(int, double)
62+
}
63+
5964
# defaults are cast to byte, taking an int facilitates resolution with constants without casting
6065
class org.elasticsearch.script.field.ByteDocValuesField @dynamic_type {
6166
byte get(int)

modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ setup:
9090
byte: [16, 32, 64, 8, 4]
9191
double: [3.141592653588, 2.141592653587]
9292
float: [1.123, 2.234]
93+
scaled_float: [-3.5, 2.5]
9394

9495

9596
- do:
@@ -1340,6 +1341,45 @@ setup:
13401341
source: "doc['scaled_float'].get(0)"
13411342
- match: { hits.hits.0.fields.field.0: 3.14 }
13421343

1344+
- do:
1345+
search:
1346+
rest_total_hits_as_int: true
1347+
body:
1348+
sort: [ { rank: asc } ]
1349+
script_fields:
1350+
field:
1351+
script:
1352+
source: "field('scaled_float').get(0.0)"
1353+
- match: { hits.hits.0.fields.field.0: 3.14 }
1354+
- match: { hits.hits.1.fields.field.0: 0.0 }
1355+
- match: { hits.hits.2.fields.field.0: -3.5 }
1356+
1357+
- do:
1358+
search:
1359+
rest_total_hits_as_int: true
1360+
body:
1361+
sort: [ { rank: asc } ]
1362+
script_fields:
1363+
field:
1364+
script:
1365+
source: "/* avoid stash */ $('scaled_float', 0.0)"
1366+
- match: { hits.hits.0.fields.field.0: 3.14 }
1367+
- match: { hits.hits.1.fields.field.0: 0.0 }
1368+
- match: { hits.hits.2.fields.field.0: -3.5 }
1369+
1370+
- do:
1371+
search:
1372+
rest_total_hits_as_int: true
1373+
body:
1374+
sort: [ { rank: asc } ]
1375+
script_fields:
1376+
field:
1377+
script:
1378+
source: "field('scaled_float').get(1, 0.0)"
1379+
- match: { hits.hits.0.fields.field.0: 0.0 }
1380+
- match: { hits.hits.1.fields.field.0: 0.0 }
1381+
- match: { hits.hits.2.fields.field.0: 2.5 }
1382+
13431383
- do:
13441384
search:
13451385
rest_total_hits_as_int: true

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
2626
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2727
import org.elasticsearch.index.fielddata.NumericDoubleValues;
28-
import org.elasticsearch.index.fielddata.ScriptDocValues.Doubles;
29-
import org.elasticsearch.index.fielddata.ScriptDocValues.DoublesSupplier;
3028
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
3129
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
3230
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
@@ -40,8 +38,8 @@
4038
import org.elasticsearch.index.mapper.TimeSeriesParams;
4139
import org.elasticsearch.index.mapper.ValueFetcher;
4240
import org.elasticsearch.index.query.SearchExecutionContext;
43-
import org.elasticsearch.script.field.DelegateDocValuesField;
4441
import org.elasticsearch.script.field.DocValuesField;
42+
import org.elasticsearch.script.field.ScaledFloatDocValuesField;
4543
import org.elasticsearch.script.field.ToScriptField;
4644
import org.elasticsearch.search.DocValueFormat;
4745
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
@@ -267,11 +265,7 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, S
267265
IndexNumericFieldData.NumericType.LONG,
268266
(dv, n) -> { throw new UnsupportedOperationException(); }
269267
).build(cache, breakerService);
270-
return new ScaledFloatIndexFieldData(
271-
scaledValues,
272-
scalingFactor,
273-
(dv, n) -> new DelegateDocValuesField(new Doubles(new DoublesSupplier(dv)), n)
274-
);
268+
return new ScaledFloatIndexFieldData(scaledValues, scalingFactor, ScaledFloatDocValuesField::new);
275269
};
276270
}
277271

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.script.field;
10+
11+
import org.apache.lucene.util.ArrayUtil;
12+
import org.elasticsearch.index.fielddata.ScriptDocValues;
13+
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
14+
15+
import java.io.IOException;
16+
import java.util.NoSuchElementException;
17+
import java.util.PrimitiveIterator;
18+
19+
public class ScaledFloatDocValuesField implements DocValuesField<Double>, ScriptDocValues.Supplier<Double> {
20+
21+
protected final SortedNumericDoubleValues input;
22+
protected final String name;
23+
24+
protected double[] values = new double[0];
25+
protected int count;
26+
27+
private ScriptDocValues.Doubles doubles = null;
28+
29+
public ScaledFloatDocValuesField(SortedNumericDoubleValues input, String name) {
30+
this.input = input;
31+
this.name = name;
32+
}
33+
34+
@Override
35+
public void setNextDocId(int docId) throws IOException {
36+
if (input.advanceExact(docId)) {
37+
resize(input.docValueCount());
38+
for (int i = 0; i < count; i++) {
39+
values[i] = input.nextValue();
40+
}
41+
} else {
42+
resize(0);
43+
}
44+
}
45+
46+
protected void resize(int newSize) {
47+
count = newSize;
48+
49+
assert count >= 0 : "size must be positive (got " + count + "): likely integer overflow?";
50+
values = ArrayUtil.grow(values, count);
51+
}
52+
53+
@Override
54+
public ScriptDocValues<Double> getScriptDocValues() {
55+
if (doubles == null) {
56+
doubles = new ScriptDocValues.Doubles(this);
57+
}
58+
59+
return doubles;
60+
}
61+
62+
@Override
63+
public Double getInternal(int index) {
64+
return values[index];
65+
}
66+
67+
@Override
68+
public String getName() {
69+
return name;
70+
}
71+
72+
@Override
73+
public boolean isEmpty() {
74+
return count == 0;
75+
}
76+
77+
@Override
78+
public int size() {
79+
return count;
80+
}
81+
82+
public double get(double defaultValue) {
83+
return get(0, defaultValue);
84+
}
85+
86+
public double get(int index, double defaultValue) {
87+
if (isEmpty() || index < 0 || index >= count) {
88+
return defaultValue;
89+
}
90+
91+
return values[index];
92+
}
93+
94+
@Override
95+
public PrimitiveIterator.OfDouble iterator() {
96+
return new PrimitiveIterator.OfDouble() {
97+
private int index = 0;
98+
99+
@Override
100+
public boolean hasNext() {
101+
return index < count;
102+
}
103+
104+
@Override
105+
public Double next() {
106+
return nextDouble();
107+
}
108+
109+
@Override
110+
public double nextDouble() {
111+
if (hasNext() == false) {
112+
throw new NoSuchElementException();
113+
}
114+
115+
return values[index++];
116+
}
117+
};
118+
}
119+
}

server/src/test/java/org/elasticsearch/index/fielddata/FloatDocValuesFieldTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.elasticsearch.script.field.DoubleDocValuesField;
1212
import org.elasticsearch.script.field.FloatDocValuesField;
13+
import org.elasticsearch.script.field.ScaledFloatDocValuesField;
1314
import org.elasticsearch.test.ESTestCase;
1415

1516
import java.io.IOException;
@@ -58,6 +59,27 @@ public void testDoubleField() throws IOException {
5859
}
5960
}
6061

62+
public void testScaledFloatField() throws IOException {
63+
double[][] values = generate(ESTestCase::randomDouble);
64+
ScaledFloatDocValuesField scaledFloatField = new ScaledFloatDocValuesField(wrap(values), "test");
65+
for (int round = 0; round < 10; round++) {
66+
int d = between(0, values.length - 1);
67+
scaledFloatField.setNextDocId(d);
68+
if (values[d].length > 0) {
69+
assertEquals(values[d][0], scaledFloatField.get(Double.MIN_VALUE), 0.0);
70+
assertEquals(values[d][0], scaledFloatField.get(0, Double.MIN_VALUE), 0.0);
71+
}
72+
assertEquals(values[d].length, scaledFloatField.size());
73+
for (int i = 0; i < values[d].length; i++) {
74+
assertEquals(values[d][i], scaledFloatField.get(i, Double.MIN_VALUE), 0.0);
75+
}
76+
int i = 0;
77+
for (double dbl : scaledFloatField) {
78+
assertEquals(values[d][i++], dbl, 0.0);
79+
}
80+
}
81+
}
82+
6183
protected double[][] generate(DoubleSupplier supplier) {
6284
double[][] values = new double[between(3, 10)][];
6385
for (int d = 0; d < values.length; d++) {

0 commit comments

Comments
 (0)