Add support for booleans in scripts (#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 #20949 * Make Booleans final and remove wrapping of `this` for getValues()
This commit is contained in:
parent
5ec2ba3166
commit
3d3dd7185d
|
@ -291,4 +291,38 @@ public interface ScriptDocValues<T> extends List<T> {
|
||||||
return geohashDistance(geohash);
|
return geohashDistance(geohash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class Booleans extends AbstractList<Boolean> implements ScriptDocValues<Boolean> {
|
||||||
|
|
||||||
|
private final SortedNumericDocValues values;
|
||||||
|
|
||||||
|
public Booleans(SortedNumericDocValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
values.setDocument(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Boolean> getValues() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getValue() {
|
||||||
|
return values.count() != 0 && values.valueAt(0) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean get(int index) {
|
||||||
|
return values.valueAt(index) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return values.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,28 +19,24 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.fielddata.plain;
|
package org.elasticsearch.index.fielddata.plain;
|
||||||
|
|
||||||
import org.apache.lucene.index.DocValues;
|
|
||||||
import org.apache.lucene.index.SortedNumericDocValues;
|
|
||||||
import org.apache.lucene.util.Accountable;
|
|
||||||
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
|
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.FieldData;
|
import org.elasticsearch.index.fielddata.FieldData;
|
||||||
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialization of {@link AtomicNumericFieldData} for integers.
|
* Specialization of {@link AtomicNumericFieldData} for integers.
|
||||||
*/
|
*/
|
||||||
abstract class AtomicLongFieldData implements AtomicNumericFieldData {
|
abstract class AtomicLongFieldData implements AtomicNumericFieldData {
|
||||||
|
|
||||||
private final long ramBytesUsed;
|
private final long ramBytesUsed;
|
||||||
|
/** True if this numeric data is for a boolean field, and so only has values 0 and 1. */
|
||||||
|
private final boolean isBoolean;
|
||||||
|
|
||||||
AtomicLongFieldData(long ramBytesUsed) {
|
AtomicLongFieldData(long ramBytesUsed, boolean isBoolean) {
|
||||||
this.ramBytesUsed = ramBytesUsed;
|
this.ramBytesUsed = ramBytesUsed;
|
||||||
|
this.isBoolean = isBoolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,7 +46,11 @@ abstract class AtomicLongFieldData implements AtomicNumericFieldData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ScriptDocValues getScriptValues() {
|
public final ScriptDocValues getScriptValues() {
|
||||||
return new ScriptDocValues.Longs(getLongValues());
|
if (isBoolean) {
|
||||||
|
return new ScriptDocValues.Booleans(getLongValues());
|
||||||
|
} else {
|
||||||
|
return new ScriptDocValues.Longs(getLongValues());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,24 +63,6 @@ abstract class AtomicLongFieldData implements AtomicNumericFieldData {
|
||||||
return FieldData.castToDouble(getLongValues());
|
return FieldData.castToDouble(getLongValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AtomicNumericFieldData empty(final int maxDoc) {
|
|
||||||
return new AtomicLongFieldData(0) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SortedNumericDocValues getLongValues() {
|
|
||||||
return DocValues.emptySortedNumeric(maxDoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Accountable> getChildResources() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class SortedNumericDVIndexFieldData extends DocValuesIndexFieldData imple
|
||||||
case DOUBLE:
|
case DOUBLE:
|
||||||
return new SortedNumericDoubleFieldData(reader, field);
|
return new SortedNumericDoubleFieldData(reader, field);
|
||||||
default:
|
default:
|
||||||
return new SortedNumericLongFieldData(reader, field);
|
return new SortedNumericLongFieldData(reader, field, numericType == NumericType.BOOLEAN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ public class SortedNumericDVIndexFieldData extends DocValuesIndexFieldData imple
|
||||||
final LeafReader reader;
|
final LeafReader reader;
|
||||||
final String field;
|
final String field;
|
||||||
|
|
||||||
SortedNumericLongFieldData(LeafReader reader, String field) {
|
SortedNumericLongFieldData(LeafReader reader, String field, boolean isBoolean) {
|
||||||
super(0L);
|
super(0L, isBoolean);
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
this.field = field;
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,12 @@ class org.elasticsearch.index.fielddata.ScriptDocValues.GeoPoints -> org.elastic
|
||||||
double geohashDistanceWithDefault(String,double)
|
double geohashDistanceWithDefault(String,double)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class org.elasticsearch.index.fielddata.ScriptDocValues.Booleans -> org.elasticsearch.index.fielddata.ScriptDocValues$Booleans extends List,Collection,Iterable,Object {
|
||||||
|
Boolean get(int)
|
||||||
|
boolean getValue()
|
||||||
|
List getValues()
|
||||||
|
}
|
||||||
|
|
||||||
# for testing.
|
# for testing.
|
||||||
# currently FeatureTest exposes overloaded constructor, field load store, and overloaded static methods
|
# currently FeatureTest exposes overloaded constructor, field load store, and overloaded static methods
|
||||||
class org.elasticsearch.painless.FeatureTest -> org.elasticsearch.painless.FeatureTest extends Object {
|
class org.elasticsearch.painless.FeatureTest -> org.elasticsearch.painless.FeatureTest extends Object {
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
index: test
|
index: test
|
||||||
type: test
|
type: test
|
||||||
id: 1
|
id: 1
|
||||||
body: { "test": "value beck", "num1": 1.0 }
|
body: { "test": "value beck", "num1": 1.0, "bool": true }
|
||||||
- do:
|
- do:
|
||||||
index:
|
index:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
type: test
|
||||||
id: 2
|
id: 2
|
||||||
body: { "test": "value beck", "num1": 2.0 }
|
body: { "test": "value beck", "num1": 2.0, "bool": false }
|
||||||
- do:
|
- do:
|
||||||
index:
|
index:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
type: test
|
||||||
id: 3
|
id: 3
|
||||||
body: { "test": "value beck", "num1": 3.0 }
|
body: { "test": "value beck", "num1": 3.0, "bool": true }
|
||||||
- do:
|
- do:
|
||||||
indices.refresh: {}
|
indices.refresh: {}
|
||||||
|
|
||||||
|
@ -95,6 +95,19 @@
|
||||||
- match: { hits.hits.1.fields.sNum1.0: 2.0 }
|
- match: { hits.hits.1.fields.sNum1.0: 2.0 }
|
||||||
- match: { hits.hits.2.fields.sNum1.0: 3.0 }
|
- match: { hits.hits.2.fields.sNum1.0: 3.0 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index: test
|
||||||
|
search:
|
||||||
|
body:
|
||||||
|
query:
|
||||||
|
script:
|
||||||
|
script:
|
||||||
|
inline: "doc['bool'].value == false"
|
||||||
|
lang: painless
|
||||||
|
|
||||||
|
- match: { hits.total: 1 }
|
||||||
|
- match: { hits.hits.0._id: "2" }
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
"Custom Script Boost":
|
"Custom Script Boost":
|
||||||
|
|
Loading…
Reference in New Issue