mirror of https://github.com/apache/lucene.git
SOLR-2136: function queries - add bool type and functions
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1131228 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
18e1bee0de
commit
1da4ffee6e
|
@ -144,6 +144,10 @@ New Features
|
|||
to IndexReader.open (in the case you have a custom IndexReaderFactory).
|
||||
(simonw via rmuir)
|
||||
|
||||
* SOLR-2136: Boolean type added to function queries, along with
|
||||
new functions exists(), if(), and(), or(), xor(), not(), def(),
|
||||
and true and false constants. (yonik)
|
||||
|
||||
|
||||
Optimizations
|
||||
----------------------
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
|
||||
package org.apache.solr.schema;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.SortField;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.CharsRef;
|
||||
import org.apache.solr.search.MutableValue;
|
||||
import org.apache.solr.search.MutableValueBool;
|
||||
import org.apache.solr.search.MutableValueInt;
|
||||
import org.apache.solr.search.QParser;
|
||||
import org.apache.solr.search.function.ValueSource;
|
||||
import org.apache.solr.search.function.OrdFieldSource;
|
||||
import org.apache.solr.search.function.*;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.Tokenizer;
|
||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||
|
@ -50,7 +54,7 @@ public class BoolField extends FieldType {
|
|||
@Override
|
||||
public ValueSource getValueSource(SchemaField field, QParser qparser) {
|
||||
field.checkFieldCacheSource(qparser);
|
||||
return new OrdFieldSource(field.name);
|
||||
return new BoolFieldSource(field.name);
|
||||
}
|
||||
|
||||
// avoid instantiating every time...
|
||||
|
@ -121,7 +125,7 @@ public class BoolField extends FieldType {
|
|||
|
||||
@Override
|
||||
public Object toObject(SchemaField sf, BytesRef term) {
|
||||
return term.bytes[0] == 'T';
|
||||
return term.bytes[term.offset] == 'T';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -148,3 +152,80 @@ public class BoolField extends FieldType {
|
|||
writer.writeBool(name, f.stringValue().charAt(0) == 'T');
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - this can be much more efficient - use OpenBitSet or Bits
|
||||
class BoolFieldSource extends ValueSource {
|
||||
protected String field;
|
||||
|
||||
public BoolFieldSource(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "bool(" + field + ')';
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DocValues getValues(Map context, IndexReader.AtomicReaderContext readerContext) throws IOException {
|
||||
final FieldCache.DocTermsIndex sindex = FieldCache.DEFAULT.getTermsIndex(readerContext.reader, field);
|
||||
|
||||
// figure out what ord maps to true
|
||||
int nord = sindex.numOrd();
|
||||
BytesRef br = new BytesRef();
|
||||
int tord = -1;
|
||||
for (int i=1; i<nord; i++) {
|
||||
sindex.lookup(i, br);
|
||||
if (br.length==1 && br.bytes[br.offset]=='T') {
|
||||
tord = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final int trueOrd = tord;
|
||||
|
||||
return new BoolDocValues(this) {
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return sindex.getOrd(doc) == trueOrd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(int doc) {
|
||||
return sindex.getOrd(doc) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueFiller getValueFiller() {
|
||||
return new ValueFiller() {
|
||||
private final MutableValueBool mval = new MutableValueBool();
|
||||
|
||||
@Override
|
||||
public MutableValue getValue() {
|
||||
return mval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillValue(int doc) {
|
||||
int ord = sindex.getOrd(doc);
|
||||
mval.value = (ord == trueOrd);
|
||||
mval.exists = (ord != 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o.getClass() == BoolFieldSource.class && this.field.equals(((BoolFieldSource)o).field);
|
||||
}
|
||||
|
||||
private static final int hcode = OrdFieldSource.class.hashCode();
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hcode + field.hashCode();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -364,9 +364,15 @@ public class FunctionQParser extends QParser {
|
|||
sp.expect(")");
|
||||
}
|
||||
else {
|
||||
if ("true".equals(id)) {
|
||||
valueSource = new BoolConstValueSource(true);
|
||||
} else if ("false".equals(id)) {
|
||||
valueSource = new BoolConstValueSource(false);
|
||||
} else {
|
||||
SchemaField f = req.getSchema().getField(id);
|
||||
valueSource = f.getType().getValueSource(f, this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.search;
|
||||
|
||||
public class MutableValueBool extends MutableValue {
|
||||
public boolean value;
|
||||
|
||||
@Override
|
||||
public Object toObject() {
|
||||
return exists ? value : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(MutableValue source) {
|
||||
MutableValueBool s = (MutableValueBool) source;
|
||||
value = s.value;
|
||||
exists = s.exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableValue duplicate() {
|
||||
MutableValueBool v = new MutableValueBool();
|
||||
v.value = this.value;
|
||||
v.exists = this.exists;
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsSameType(Object other) {
|
||||
MutableValueBool b = (MutableValueBool)other;
|
||||
return value == b.value && exists == b.exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareSameType(Object other) {
|
||||
MutableValueBool b = (MutableValueBool)other;
|
||||
if (value != b.value) return value ? 1 : 0;
|
||||
if (exists == b.exists) return 0;
|
||||
return exists ? 1 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value ? 2 : (exists ? 1 : 0);
|
||||
}
|
||||
}
|
|
@ -579,6 +579,134 @@ public abstract class ValueSourceParser implements NamedListInitializedPlugin {
|
|||
return new NumDocsValueSource();
|
||||
}
|
||||
});
|
||||
|
||||
addParser("true", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
return new BoolConstValueSource(true);
|
||||
}
|
||||
});
|
||||
|
||||
addParser("false", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
return new BoolConstValueSource(false);
|
||||
}
|
||||
});
|
||||
|
||||
addParser("exists", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
ValueSource vs = fp.parseValueSource();
|
||||
return new SimpleBoolFunction(vs) {
|
||||
@Override
|
||||
protected String name() {
|
||||
return "exists";
|
||||
}
|
||||
@Override
|
||||
protected boolean func(int doc, DocValues vals) {
|
||||
return vals.exists(doc);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
addParser("not", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
ValueSource vs = fp.parseValueSource();
|
||||
return new SimpleBoolFunction(vs) {
|
||||
@Override
|
||||
protected boolean func(int doc, DocValues vals) {
|
||||
return !vals.boolVal(doc);
|
||||
}
|
||||
@Override
|
||||
protected String name() {
|
||||
return "not";
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
addParser("and", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
List<ValueSource> sources = fp.parseValueSourceList();
|
||||
return new MultiBoolFunction(sources) {
|
||||
@Override
|
||||
protected String name() {
|
||||
return "and";
|
||||
}
|
||||
@Override
|
||||
protected boolean func(int doc, DocValues[] vals) {
|
||||
for (DocValues dv : vals)
|
||||
if (!dv.boolVal(doc)) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
addParser("or", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
List<ValueSource> sources = fp.parseValueSourceList();
|
||||
return new MultiBoolFunction(sources) {
|
||||
@Override
|
||||
protected String name() {
|
||||
return "or";
|
||||
}
|
||||
@Override
|
||||
protected boolean func(int doc, DocValues[] vals) {
|
||||
for (DocValues dv : vals)
|
||||
if (dv.boolVal(doc)) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
addParser("xor", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
List<ValueSource> sources = fp.parseValueSourceList();
|
||||
return new MultiBoolFunction(sources) {
|
||||
@Override
|
||||
protected String name() {
|
||||
return "xor";
|
||||
}
|
||||
@Override
|
||||
protected boolean func(int doc, DocValues[] vals) {
|
||||
int nTrue=0, nFalse=0;
|
||||
for (DocValues dv : vals) {
|
||||
if (dv.boolVal(doc)) nTrue++;
|
||||
else nFalse++;
|
||||
}
|
||||
return nTrue != 0 && nFalse != 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
addParser("if", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
ValueSource ifValueSource = fp.parseValueSource();
|
||||
ValueSource trueValueSource = fp.parseValueSource();
|
||||
ValueSource falseValueSource = fp.parseValueSource();
|
||||
|
||||
return new IfFunction(ifValueSource, trueValueSource, falseValueSource);
|
||||
}
|
||||
});
|
||||
|
||||
addParser("def", new ValueSourceParser() {
|
||||
@Override
|
||||
public ValueSource parse(FunctionQParser fp) throws ParseException {
|
||||
return new DefFunction(fp.parseValueSourceList());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static TInfo parseTerm(FunctionQParser fp) throws ParseException {
|
||||
|
@ -857,6 +985,11 @@ class LongConstValueSource extends ConstNumberSource {
|
|||
public Number getNumber() {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBool() {
|
||||
return constant != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -981,3 +1114,69 @@ abstract class Double2Parser extends NamedParser {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BoolConstValueSource extends ConstNumberSource {
|
||||
final boolean constant;
|
||||
|
||||
public BoolConstValueSource(boolean constant) {
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "const(" + constant + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
return new BoolDocValues(this) {
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return constant;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return constant ? 0x12345678 : 0x87654321;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (BoolConstValueSource.class != o.getClass()) return false;
|
||||
BoolConstValueSource other = (BoolConstValueSource) o;
|
||||
return this.constant == other.constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return constant ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return constant ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return constant ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return constant ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumber() {
|
||||
return constant ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBool() {
|
||||
return constant;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package org.apache.solr.search.function;
|
||||
|
||||
import org.apache.solr.search.MutableValue;
|
||||
import org.apache.solr.search.MutableValueBool;
|
||||
import org.apache.solr.search.MutableValueInt;
|
||||
|
||||
public abstract class BoolDocValues extends DocValues {
|
||||
protected final ValueSource vs;
|
||||
|
||||
public BoolDocValues(ValueSource vs) {
|
||||
this.vs = vs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean boolVal(int doc);
|
||||
|
||||
@Override
|
||||
public byte byteVal(int doc) {
|
||||
return boolVal(doc) ? (byte)1 : (byte)0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short shortVal(int doc) {
|
||||
return boolVal(doc) ? (short)1 : (short)0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatVal(int doc) {
|
||||
return boolVal(doc) ? (float)1 : (float)0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intVal(int doc) {
|
||||
return boolVal(doc) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longVal(int doc) {
|
||||
return boolVal(doc) ? (long)1 : (long)0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleVal(int doc) {
|
||||
return boolVal(doc) ? (double)1 : (double)0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String strVal(int doc) {
|
||||
return Boolean.toString(boolVal(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object objectVal(int doc) {
|
||||
return exists(doc) ? boolVal(doc) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return vs.description() + '=' + strVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueFiller getValueFiller() {
|
||||
return new ValueFiller() {
|
||||
private final MutableValueBool mval = new MutableValueBool();
|
||||
|
||||
@Override
|
||||
public MutableValue getValue() {
|
||||
return mval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillValue(int doc) {
|
||||
mval.value = boolVal(doc);
|
||||
mval.exists = exists(doc);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.solr.search.function;
|
||||
|
||||
|
||||
public abstract class BoolFunction extends ValueSource {
|
||||
// TODO: placeholder to return type, among other common future functionality
|
||||
}
|
|
@ -26,4 +26,5 @@ public abstract class ConstNumberSource extends ValueSource {
|
|||
public abstract float getFloat();
|
||||
public abstract double getDouble();
|
||||
public abstract Number getNumber();
|
||||
public abstract boolean getBool();
|
||||
}
|
||||
|
|
|
@ -66,6 +66,10 @@ public class ConstValueSource extends ConstNumberSource {
|
|||
public Object objectVal(int doc) {
|
||||
return constant;
|
||||
}
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return constant != 0.0f;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -105,4 +109,9 @@ public class ConstValueSource extends ConstNumberSource {
|
|||
public Number getNumber() {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBool() {
|
||||
return constant != 0.0f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package org.apache.solr.search.function;
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.apache.lucene.index.IndexReader.AtomicReaderContext;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DefFunction extends MultiFunction {
|
||||
public DefFunction(List<ValueSource> sources) {
|
||||
super(sources);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String name() {
|
||||
return "def";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DocValues getValues(Map fcontext, AtomicReaderContext readerContext) throws IOException {
|
||||
|
||||
|
||||
return new Values(valsArr(sources, fcontext, readerContext)) {
|
||||
final int upto = valsArr.length - 1;
|
||||
|
||||
private DocValues get(int doc) {
|
||||
for (int i=0; i<upto; i++) {
|
||||
DocValues vals = valsArr[i];
|
||||
if (vals.exists(doc)) {
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
return valsArr[upto];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte byteVal(int doc) {
|
||||
return get(doc).byteVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short shortVal(int doc) {
|
||||
return get(doc).shortVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatVal(int doc) {
|
||||
return get(doc).floatVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intVal(int doc) {
|
||||
return get(doc).intVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longVal(int doc) {
|
||||
return get(doc).longVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleVal(int doc) {
|
||||
return get(doc).doubleVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String strVal(int doc) {
|
||||
return get(doc).strVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return get(doc).boolVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bytesVal(int doc, BytesRef target) {
|
||||
return get(doc).bytesVal(doc, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object objectVal(int doc) {
|
||||
return get(doc).objectVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(int doc) {
|
||||
// return true if any source is exists?
|
||||
for (DocValues vals : valsArr) {
|
||||
if (vals.exists(doc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueFiller getValueFiller() {
|
||||
// TODO: need ValueSource.type() to determine correct type
|
||||
return super.getValueFiller();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -48,6 +48,10 @@ public abstract class DocValues {
|
|||
// TODO: should we make a termVal, returns BytesRef?
|
||||
public String strVal(int doc) { throw new UnsupportedOperationException(); }
|
||||
|
||||
public boolean boolVal(int doc) {
|
||||
return intVal(doc) != 0;
|
||||
}
|
||||
|
||||
/** returns the bytes representation of the string val - TODO: should this return the indexed raw bytes not? */
|
||||
public boolean bytesVal(int doc, BytesRef target) {
|
||||
String s = strVal(doc);
|
||||
|
|
|
@ -115,4 +115,9 @@ public class DoubleConstValueSource extends ConstNumberSource {
|
|||
public Number getNumber() {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBool() {
|
||||
return constant != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,11 @@ public abstract class DoubleDocValues extends DocValues {
|
|||
return (long)doubleVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return doubleVal(doc) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract double doubleVal(int doc);
|
||||
|
||||
|
|
|
@ -53,40 +53,15 @@ public class DoubleFieldSource extends NumericFieldCacheSource<DoubleValues> {
|
|||
final double[] arr = vals.values;
|
||||
final Bits valid = vals.valid;
|
||||
|
||||
return new DocValues() {
|
||||
@Override
|
||||
public float floatVal(int doc) {
|
||||
return (float) arr[doc];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intVal(int doc) {
|
||||
return (int) arr[doc];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longVal(int doc) {
|
||||
return (long) arr[doc];
|
||||
}
|
||||
|
||||
return new DoubleDocValues(this) {
|
||||
@Override
|
||||
public double doubleVal(int doc) {
|
||||
return arr[doc];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String strVal(int doc) {
|
||||
return Double.toString(arr[doc]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object objectVal(int doc) {
|
||||
return valid.get(doc) ? arr[doc] : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return description() + '=' + doubleVal(doc);
|
||||
public boolean exists(int doc) {
|
||||
return valid.get(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.solr.search.function;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.IndexReader.AtomicReaderContext;
|
||||
import org.apache.lucene.search.Explanation;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class IfFunction extends BoolFunction {
|
||||
private ValueSource ifSource;
|
||||
private ValueSource trueSource;
|
||||
private ValueSource falseSource;
|
||||
|
||||
|
||||
public IfFunction(ValueSource ifSource, ValueSource trueSource, ValueSource falseSource) {
|
||||
this.ifSource = ifSource;
|
||||
this.trueSource = trueSource;
|
||||
this.falseSource = falseSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
final DocValues ifVals = ifSource.getValues(context, readerContext);
|
||||
final DocValues trueVals = trueSource.getValues(context, readerContext);
|
||||
final DocValues falseVals = falseSource.getValues(context, readerContext);
|
||||
|
||||
return new DocValues() {
|
||||
@Override
|
||||
public byte byteVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.byteVal(doc) : falseVals.byteVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short shortVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.shortVal(doc) : falseVals.shortVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.floatVal(doc) : falseVals.floatVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.intVal(doc) : falseVals.intVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.longVal(doc) : falseVals.longVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.doubleVal(doc) : falseVals.doubleVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String strVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.strVal(doc) : falseVals.strVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.boolVal(doc) : falseVals.boolVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bytesVal(int doc, BytesRef target) {
|
||||
return ifVals.boolVal(doc) ? trueVals.bytesVal(doc, target) : falseVals.bytesVal(doc, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object objectVal(int doc) {
|
||||
return ifVals.boolVal(doc) ? trueVals.objectVal(doc) : falseVals.objectVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(int doc) {
|
||||
return true; // TODO: flow through to any sub-sources?
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueFiller getValueFiller() {
|
||||
// TODO: we need types of trueSource / falseSource to handle this
|
||||
// for now, use float.
|
||||
return super.getValueFiller();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return "if(" + ifVals.toString(doc) + ',' + trueVals.toString(doc) + ',' + falseVals.toString(doc) + ')';
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "if(" + ifSource.description() + ',' + trueSource.description() + ',' + falseSource + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = ifSource.hashCode();
|
||||
h = h * 31 + trueSource.hashCode();
|
||||
h = h * 31 + falseSource.hashCode();
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof IfFunction)) return false;
|
||||
IfFunction other = (IfFunction)o;
|
||||
return ifSource.equals(other.ifSource)
|
||||
&& trueSource.equals(other.trueSource)
|
||||
&& falseSource.equals(other.falseSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWeight(Map context, IndexSearcher searcher) throws IOException {
|
||||
ifSource.createWeight(context, searcher);
|
||||
trueSource.createWeight(context, searcher);
|
||||
falseSource.createWeight(context, searcher);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,11 @@ public abstract class LongDocValues extends DocValues {
|
|||
return (double)longVal(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return longVal(doc) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String strVal(int doc) {
|
||||
return Long.toString(longVal(doc));
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.solr.search.function;
|
||||
|
||||
import org.apache.lucene.index.IndexReader.AtomicReaderContext;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public abstract class MultiBoolFunction extends BoolFunction {
|
||||
protected final List<ValueSource> sources;
|
||||
|
||||
public MultiBoolFunction(List<ValueSource> sources) {
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
protected abstract String name();
|
||||
|
||||
protected abstract boolean func(int doc, DocValues[] vals);
|
||||
|
||||
@Override
|
||||
public BoolDocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
final DocValues[] vals = new DocValues[sources.size()];
|
||||
int i=0;
|
||||
for (ValueSource source : sources) {
|
||||
vals[i++] = source.getValues(context, readerContext);
|
||||
}
|
||||
|
||||
return new BoolDocValues(this) {
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return func(doc, vals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
StringBuilder sb = new StringBuilder(name());
|
||||
sb.append('(');
|
||||
boolean first = true;
|
||||
for (DocValues dv : vals) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(dv.toString(doc));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
StringBuilder sb = new StringBuilder(name());
|
||||
sb.append('(');
|
||||
boolean first = true;
|
||||
for (ValueSource source : sources) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(source.description());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sources.hashCode() + name().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this.getClass() != o.getClass()) return false;
|
||||
MultiBoolFunction other = (MultiBoolFunction)o;
|
||||
return this.sources.equals(other.sources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWeight(Map context, IndexSearcher searcher) throws IOException {
|
||||
for (ValueSource source : sources) {
|
||||
source.createWeight(context, searcher);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package org.apache.solr.search.function;
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.apache.lucene.index.IndexReader.AtomicReaderContext;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public abstract class MultiFunction extends ValueSource {
|
||||
protected final List<ValueSource> sources;
|
||||
|
||||
public MultiFunction(List<ValueSource> sources) {
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
abstract protected String name();
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description(name(), sources);
|
||||
}
|
||||
|
||||
public static String description(String name, List<ValueSource> sources) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name).append('(');
|
||||
boolean firstTime=true;
|
||||
for (ValueSource source : sources) {
|
||||
if (firstTime) {
|
||||
firstTime=false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(source);
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static DocValues[] valsArr(List<ValueSource> sources, Map fcontext, AtomicReaderContext readerContext) throws IOException {
|
||||
final DocValues[] valsArr = new DocValues[sources.size()];
|
||||
int i=0;
|
||||
for (ValueSource source : sources) {
|
||||
valsArr[i++] = source.getValues(fcontext, readerContext);
|
||||
}
|
||||
return valsArr;
|
||||
}
|
||||
|
||||
public class Values extends DocValues {
|
||||
final DocValues[] valsArr;
|
||||
|
||||
public Values(DocValues[] valsArr) {
|
||||
this.valsArr = valsArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return MultiFunction.toString(name(), valsArr, doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueFiller getValueFiller() {
|
||||
// TODO: need ValueSource.type() to determine correct type
|
||||
return super.getValueFiller();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String toString(String name, DocValues[] valsArr, int doc) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name).append('(');
|
||||
boolean firstTime=true;
|
||||
for (DocValues vals : valsArr) {
|
||||
if (firstTime) {
|
||||
firstTime=false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(vals.toString(doc));
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWeight(Map context, IndexSearcher searcher) throws IOException {
|
||||
for (ValueSource source : sources)
|
||||
source.createWeight(context, searcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sources.hashCode() + name().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this.getClass() != o.getClass()) return false;
|
||||
MultiFunction other = (MultiFunction)o;
|
||||
return this.sources.equals(other.sources);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.solr.search.function;
|
||||
|
||||
import org.apache.lucene.index.IndexReader.AtomicReaderContext;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public abstract class SimpleBoolFunction extends BoolFunction {
|
||||
protected final ValueSource source;
|
||||
|
||||
public SimpleBoolFunction(ValueSource source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
protected abstract String name();
|
||||
|
||||
protected abstract boolean func(int doc, DocValues vals);
|
||||
|
||||
@Override
|
||||
public BoolDocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
final DocValues vals = source.getValues(context, readerContext);
|
||||
return new BoolDocValues(this) {
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return func(doc, vals);
|
||||
}
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return name() + '(' + vals.toString(doc) + ')';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return name() + '(' + source.description() + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return source.hashCode() + name().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this.getClass() != o.getClass()) return false;
|
||||
SingleFunction other = (SingleFunction)o;
|
||||
return this.source.equals(other.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWeight(Map context, IndexSearcher searcher) throws IOException {
|
||||
source.createWeight(context, searcher);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,11 @@ public abstract class StrDocValues extends DocValues {
|
|||
return exists(doc) ? strVal(doc) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return exists(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int doc) {
|
||||
return vs.description() + "='" + strVal(doc) + "'";
|
||||
|
|
|
@ -78,6 +78,10 @@ public abstract class StringIndexDocValues extends DocValues {
|
|||
return spareChars.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean boolVal(int doc) {
|
||||
return exists(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Object objectVal(int doc); // force subclasses to override
|
||||
|
|
|
@ -120,6 +120,28 @@ public class TestQueryTypes extends AbstractSolrTestCase {
|
|||
,"//result[@numFound='1']"
|
||||
);
|
||||
|
||||
// exists()
|
||||
assertQ(req( "fq","id:999", "q", "{!frange l=1 u=1}if(exists("+f+"),1,0)" )
|
||||
,"//result[@numFound='1']"
|
||||
);
|
||||
|
||||
// boolean value of non-zero values (just leave off the exists from the prev test)
|
||||
assertQ(req( "fq","id:999", "q", "{!frange l=1 u=1}if("+f+",1,0)" )
|
||||
,"//result[@numFound='1']"
|
||||
);
|
||||
|
||||
if (!"id".equals(f)) {
|
||||
assertQ(req( "fq","id:1", "q", "{!frange l=1 u=1}if(exists("+f+"),1,0)" )
|
||||
,"//result[@numFound='0']"
|
||||
);
|
||||
|
||||
// boolean value of zero/missing values (just leave off the exists from the prev test)
|
||||
assertQ(req( "fq","id:1", "q", "{!frange l=1 u=1}if("+f+",1,0)" )
|
||||
,"//result[@numFound='0']"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// function query... just make sure it doesn't throw an exception
|
||||
if ("v_s".equals(f)) continue; // in this context, functions must be able to be interpreted as a float
|
||||
assertQ(req( "q", "+id:999 _val_:\"" + f + "\"")
|
||||
|
|
|
@ -581,4 +581,56 @@ public class TestFunctionQuery extends SolrTestCaseJ4 {
|
|||
purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanFunctions() throws Exception {
|
||||
assertU(adoc("id", "1", "text", "hello", "foo_s","A", "foo_ti", "0", "foo_tl","0"));
|
||||
assertU(adoc("id", "2" , "foo_ti","10", "foo_tl","11"));
|
||||
assertU(commit());
|
||||
|
||||
// true and false functions and constants
|
||||
assertJQ(req("q", "id:1", "fl", "t:true(),f:false(),tt:{!func}true,ff:{!func}false")
|
||||
, "/response/docs/[0]=={'t':true,'f':false,'tt':true,'ff':false}");
|
||||
|
||||
// test that exists(query) depends on the query matching the document
|
||||
assertJQ(req("q", "id:1", "fl", "t:exists(query($q1)),f:exists(query($q2))", "q1","text:hello", "q2","text:there")
|
||||
, "/response/docs/[0]=={'t':true,'f':false}");
|
||||
|
||||
// test if()
|
||||
assertJQ(req("q", "id:1", "fl", "a1:if(true,'A','B')", "fl","b1:if(false,'A','B')")
|
||||
, "/response/docs/[0]=={'a1':'A', 'b1':'B'}");
|
||||
|
||||
// test boolean operators
|
||||
assertJQ(req("q", "id:1", "fl", "t1:and(true,true)", "fl","f1:and(true,false)", "fl","f2:and(false,true)", "fl","f3:and(false,false)")
|
||||
, "/response/docs/[0]=={'t1':true, 'f1':false, 'f2':false, 'f3':false}");
|
||||
assertJQ(req("q", "id:1", "fl", "t1:or(true,true)", "fl","t2:or(true,false)", "fl","t3:or(false,true)", "fl","f1:or(false,false)")
|
||||
, "/response/docs/[0]=={'t1':true, 't2':true, 't3':true, 'f1':false}");
|
||||
assertJQ(req("q", "id:1", "fl", "f1:xor(true,true)", "fl","t1:xor(true,false)", "fl","t2:xor(false,true)", "fl","f2:xor(false,false)")
|
||||
, "/response/docs/[0]=={'t1':true, 't2':true, 'f1':false, 'f2':false}");
|
||||
assertJQ(req("q", "id:1", "fl", "t:not(false),f:not(true)")
|
||||
, "/response/docs/[0]=={'t':true, 'f':false}");
|
||||
|
||||
|
||||
// def(), the default function that returns the first value that exists
|
||||
assertJQ(req("q", "id:1", "fl", "x:def(id,123.0), y:def(foo_f,234.0)")
|
||||
, "/response/docs/[0]=={'x':1.0, 'y':234.0}");
|
||||
assertJQ(req("q", "id:1", "fl", "x:def(foo_s,'Q'), y:def(missing_s,'W')")
|
||||
, "/response/docs/[0]=={'x':'A', 'y':'W'}");
|
||||
|
||||
// test constant conversion to boolean
|
||||
assertJQ(req("q", "id:1", "fl", "a:not(0), b:not(1), c:not(0.0), d:not(1.1), e:not('A')")
|
||||
, "/response/docs/[0]=={'a':true, 'b':false, 'c':true, 'd':false, 'e':false}");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPseudoFieldFunctions() throws Exception {
|
||||
assertU(adoc("id", "1", "text", "hello", "foo_s","A"));
|
||||
assertU(adoc("id", "2"));
|
||||
assertU(commit());
|
||||
|
||||
assertJQ(req("q", "id:1", "fl", "a:1,b:2.0,c:'X',d:{!func}foo_s,e:{!func}bar_s") // if exists() is false, no pseudo-field should be added
|
||||
, "/response/docs/[0]=={'a':1, 'b':2.0,'c':'X','d':'A'}");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue