Skip to content

Commit 3d3dd71

Browse files
authored
Add support for booleans in scripts (elastic#20950)
* Scripting: Add support for booleans in scripts Since 2.0, booleans have been represented as numeric fields (longs). However, in scripts, this is odd, since you expect doing a comparison against a boolean to work. While languages like groovy will auto convert between booleans and longs, painless does not. This changes the doc values accessor for boolean fields in scripts to return Boolean objects instead of Long objects. closes elastic#20949 * Make Booleans final and remove wrapping of `this` for getValues()
1 parent 5ec2ba3 commit 3d3dd71

File tree

5 files changed

+69
-34
lines changed

5 files changed

+69
-34
lines changed

core/src/main/java/org/elasticsearch/index/fielddata/ScriptDocValues.java

+34
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,38 @@ public double geohashDistanceWithDefault(String geohash, double defaultValue) {
291291
return geohashDistance(geohash);
292292
}
293293
}
294+
295+
final class Booleans extends AbstractList<Boolean> implements ScriptDocValues<Boolean> {
296+
297+
private final SortedNumericDocValues values;
298+
299+
public Booleans(SortedNumericDocValues values) {
300+
this.values = values;
301+
}
302+
303+
@Override
304+
public void setNextDocId(int docId) {
305+
values.setDocument(docId);
306+
}
307+
308+
@Override
309+
public List<Boolean> getValues() {
310+
return this;
311+
}
312+
313+
public boolean getValue() {
314+
return values.count() != 0 && values.valueAt(0) == 1;
315+
}
316+
317+
@Override
318+
public Boolean get(int index) {
319+
return values.valueAt(index) == 1;
320+
}
321+
322+
@Override
323+
public int size() {
324+
return values.count();
325+
}
326+
327+
}
294328
}

core/src/main/java/org/elasticsearch/index/fielddata/plain/AtomicLongFieldData.java

+10-28
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,24 @@
1919

2020
package org.elasticsearch.index.fielddata.plain;
2121

22-
import org.apache.lucene.index.DocValues;
23-
import org.apache.lucene.index.SortedNumericDocValues;
24-
import org.apache.lucene.util.Accountable;
2522
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
2623
import org.elasticsearch.index.fielddata.FieldData;
2724
import org.elasticsearch.index.fielddata.ScriptDocValues;
2825
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
2926
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
3027

31-
import java.util.Collection;
32-
import java.util.Collections;
33-
34-
3528
/**
3629
* Specialization of {@link AtomicNumericFieldData} for integers.
3730
*/
3831
abstract class AtomicLongFieldData implements AtomicNumericFieldData {
3932

4033
private final long ramBytesUsed;
34+
/** True if this numeric data is for a boolean field, and so only has values 0 and 1. */
35+
private final boolean isBoolean;
4136

42-
AtomicLongFieldData(long ramBytesUsed) {
37+
AtomicLongFieldData(long ramBytesUsed, boolean isBoolean) {
4338
this.ramBytesUsed = ramBytesUsed;
39+
this.isBoolean = isBoolean;
4440
}
4541

4642
@Override
@@ -50,7 +46,11 @@ public long ramBytesUsed() {
5046

5147
@Override
5248
public final ScriptDocValues getScriptValues() {
53-
return new ScriptDocValues.Longs(getLongValues());
49+
if (isBoolean) {
50+
return new ScriptDocValues.Booleans(getLongValues());
51+
} else {
52+
return new ScriptDocValues.Longs(getLongValues());
53+
}
5454
}
5555

5656
@Override
@@ -63,24 +63,6 @@ public final SortedNumericDoubleValues getDoubleValues() {
6363
return FieldData.castToDouble(getLongValues());
6464
}
6565

66-
public static AtomicNumericFieldData empty(final int maxDoc) {
67-
return new AtomicLongFieldData(0) {
68-
69-
@Override
70-
public SortedNumericDocValues getLongValues() {
71-
return DocValues.emptySortedNumeric(maxDoc);
72-
}
73-
74-
@Override
75-
public Collection<Accountable> getChildResources() {
76-
return Collections.emptyList();
77-
}
78-
79-
};
80-
}
81-
8266
@Override
83-
public void close() {
84-
}
85-
67+
public void close() {}
8668
}

core/src/main/java/org/elasticsearch/index/fielddata/plain/SortedNumericDVIndexFieldData.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public AtomicNumericFieldData load(LeafReaderContext context) {
9696
case DOUBLE:
9797
return new SortedNumericDoubleFieldData(reader, field);
9898
default:
99-
return new SortedNumericLongFieldData(reader, field);
99+
return new SortedNumericLongFieldData(reader, field, numericType == NumericType.BOOLEAN);
100100
}
101101
}
102102

@@ -117,8 +117,8 @@ static final class SortedNumericLongFieldData extends AtomicLongFieldData {
117117
final LeafReader reader;
118118
final String field;
119119

120-
SortedNumericLongFieldData(LeafReader reader, String field) {
121-
super(0L);
120+
SortedNumericLongFieldData(LeafReader reader, String field, boolean isBoolean) {
121+
super(0L, isBoolean);
122122
this.reader = reader;
123123
this.field = field;
124124
}

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

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ class org.elasticsearch.index.fielddata.ScriptDocValues.GeoPoints -> org.elastic
101101
double geohashDistanceWithDefault(String,double)
102102
}
103103

104+
class org.elasticsearch.index.fielddata.ScriptDocValues.Booleans -> org.elasticsearch.index.fielddata.ScriptDocValues$Booleans extends List,Collection,Iterable,Object {
105+
Boolean get(int)
106+
boolean getValue()
107+
List getValues()
108+
}
109+
104110
# for testing.
105111
# currently FeatureTest exposes overloaded constructor, field load store, and overloaded static methods
106112
class org.elasticsearch.painless.FeatureTest -> org.elasticsearch.painless.FeatureTest extends Object {

modules/lang-painless/src/test/resources/rest-api-spec/test/plan_a/30_search.yaml

+16-3
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66
index: test
77
type: test
88
id: 1
9-
body: { "test": "value beck", "num1": 1.0 }
9+
body: { "test": "value beck", "num1": 1.0, "bool": true }
1010
- do:
1111
index:
1212
index: test
1313
type: test
1414
id: 2
15-
body: { "test": "value beck", "num1": 2.0 }
15+
body: { "test": "value beck", "num1": 2.0, "bool": false }
1616
- do:
1717
index:
1818
index: test
1919
type: test
2020
id: 3
21-
body: { "test": "value beck", "num1": 3.0 }
21+
body: { "test": "value beck", "num1": 3.0, "bool": true }
2222
- do:
2323
indices.refresh: {}
2424

@@ -95,6 +95,19 @@
9595
- match: { hits.hits.1.fields.sNum1.0: 2.0 }
9696
- match: { hits.hits.2.fields.sNum1.0: 3.0 }
9797

98+
- do:
99+
index: test
100+
search:
101+
body:
102+
query:
103+
script:
104+
script:
105+
inline: "doc['bool'].value == false"
106+
lang: painless
107+
108+
- match: { hits.total: 1 }
109+
- match: { hits.hits.0._id: "2" }
110+
98111
---
99112

100113
"Custom Script Boost":

0 commit comments

Comments
 (0)