LUCENE-7723: Add hashCode and equals to DoubleValuesSource

This commit is contained in:
Alan Woodward 2017-05-08 11:24:17 +01:00
parent 808171ac00
commit 1a278ae89b
10 changed files with 454 additions and 241 deletions

View File

@ -89,6 +89,9 @@ API Changes
* LUCENE-7867: The deprecated Token class is now only available in the test * LUCENE-7867: The deprecated Token class is now only available in the test
framework (Alan Woodward, Adrien Grand) framework (Alan Woodward, Adrien Grand)
* LUCENE-7723: DoubleValuesSource enforces implementation of equals() and
hashCode() (Alan Woodward)
Bug Fixes Bug Fixes
* LUCENE-7626: IndexWriter will no longer accept broken token offsets * LUCENE-7626: IndexWriter will no longer accept broken token offsets

View File

@ -20,9 +20,7 @@ package org.apache.lucene.search;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.function.DoubleToLongFunction; import java.util.function.DoubleToLongFunction;
import java.util.function.DoubleUnaryOperator;
import java.util.function.LongToDoubleFunction; import java.util.function.LongToDoubleFunction;
import java.util.function.ToDoubleBiFunction;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
@ -76,14 +74,33 @@ public abstract class DoubleValuesSource {
return new DoubleValuesSortField(this, reverse); return new DoubleValuesSortField(this, reverse);
} }
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
@Override
public abstract String toString();
/** /**
* Convert to a LongValuesSource by casting the double values to longs * Convert to a LongValuesSource by casting the double values to longs
*/ */
public final LongValuesSource toLongValuesSource() { public final LongValuesSource toLongValuesSource() {
return new LongValuesSource() { return new LongDoubleValuesSource(this);
@Override }
private static class LongDoubleValuesSource extends LongValuesSource {
private final DoubleValuesSource inner;
private LongDoubleValuesSource(DoubleValuesSource inner) {
this.inner = inner;
}
@Override
public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException { public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
DoubleValues in = DoubleValuesSource.this.getValues(ctx, scores); DoubleValues in = inner.getValues(ctx, scores);
return new LongValues() { return new LongValues() {
@Override @Override
public long longValue() throws IOException { public long longValue() throws IOException {
@ -99,9 +116,27 @@ public abstract class DoubleValuesSource {
@Override @Override
public boolean needsScores() { public boolean needsScores() {
return DoubleValuesSource.this.needsScores(); return inner.needsScores();
} }
};
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LongDoubleValuesSource that = (LongDoubleValuesSource) o;
return Objects.equals(inner, that.inner);
}
@Override
public int hashCode() {
return Objects.hash(inner);
}
@Override
public String toString() {
return "long(" + inner.toString() + ")";
}
} }
/** /**
@ -164,115 +199,80 @@ public abstract class DoubleValuesSource {
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) { public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) {
return scoreExplanation; return scoreExplanation;
} }
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
@Override
public String toString() {
return "scores";
}
}; };
/** /**
* Creates a DoubleValuesSource that always returns a constant value * Creates a DoubleValuesSource that always returns a constant value
*/ */
public static DoubleValuesSource constant(double value) { public static DoubleValuesSource constant(double value) {
return new DoubleValuesSource() { return new ConstantValuesSource(value);
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return value;
}
@Override
public boolean advanceExact(int doc) throws IOException {
return true;
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) {
return Explanation.match((float) value, "constant(" + value + ")");
}
@Override
public String toString() {
return "constant(" + value + ")";
}
};
} }
/** private static class ConstantValuesSource extends DoubleValuesSource {
* Creates a DoubleValuesSource that is a function of another DoubleValuesSource
*/
public static DoubleValuesSource function(DoubleValuesSource in, String description, DoubleUnaryOperator function) {
return new DoubleValuesSource() {
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
DoubleValues inputs = in.getValues(ctx, scores);
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return function.applyAsDouble(inputs.doubleValue());
}
@Override private final double value;
public boolean advanceExact(int doc) throws IOException {
return inputs.advanceExact(doc);
}
};
}
@Override private ConstantValuesSource(double value) {
public boolean needsScores() { this.value = value;
return in.needsScores(); }
}
@Override @Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException { public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
Explanation inner = in.explain(ctx, docId, scoreExplanation); return new DoubleValues() {
return Explanation.match((float) function.applyAsDouble(inner.getValue()), description + ", computed from:", inner, scoreExplanation); @Override
} public double doubleValue() throws IOException {
}; return value;
} }
/** @Override
* Creates a DoubleValuesSource that is a function of another DoubleValuesSource and a score public boolean advanceExact(int doc) throws IOException {
* @param in the DoubleValuesSource to use as an input return true;
* @param description a description of the function }
* @param function a function of the form (source, score) == result };
*/ }
public static DoubleValuesSource scoringFunction(DoubleValuesSource in, String description, ToDoubleBiFunction<Double, Double> function) {
return new DoubleValuesSource() {
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
DoubleValues inputs = in.getValues(ctx, scores);
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return function.applyAsDouble(inputs.doubleValue(), scores.doubleValue());
}
@Override @Override
public boolean advanceExact(int doc) throws IOException { public boolean needsScores() {
return inputs.advanceExact(doc); return false;
} }
};
}
@Override @Override
public boolean needsScores() { public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) {
return true; return Explanation.match((float) value, "constant(" + value + ")");
} }
@Override @Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException { public int hashCode() {
Explanation inner = in.explain(ctx, docId, scoreExplanation); return Objects.hash(value);
return Explanation.match((float) function.applyAsDouble((double)inner.getValue(), (double)scoreExplanation.getValue()), }
description + ", computed from:", inner, scoreExplanation);
} @Override
}; public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConstantValuesSource that = (ConstantValuesSource) o;
return Double.compare(that.value, value) == 0;
}
@Override
public String toString() {
return "constant(" + value + ")";
}
} }
/** /**
@ -312,6 +312,11 @@ public abstract class DoubleValuesSource {
Objects.equals(decoder, that.decoder); Objects.equals(decoder, that.decoder);
} }
@Override
public String toString() {
return "double(" + field + ")";
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(field, decoder); return Objects.hash(field, decoder);
@ -342,9 +347,9 @@ public abstract class DoubleValuesSource {
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException { public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException {
DoubleValues values = getValues(ctx, null); DoubleValues values = getValues(ctx, null);
if (values.advanceExact(docId)) if (values.advanceExact(docId))
return Explanation.match((float)values.doubleValue(), "double(" + field + ")"); return Explanation.match((float)values.doubleValue(), this.toString());
else else
return Explanation.noMatch("double(" + field + ")"); return Explanation.noMatch(this.toString());
} }
} }

View File

@ -52,6 +52,15 @@ public abstract class LongValuesSource {
*/ */
public abstract boolean needsScores(); public abstract boolean needsScores();
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
@Override
public abstract String toString();
/** /**
* Create a sort field based on the value of this producer * Create a sort field based on the value of this producer
* @param reverse true if the sort should be decreasing * @param reverse true if the sort should be decreasing
@ -78,27 +87,55 @@ public abstract class LongValuesSource {
* Creates a LongValuesSource that always returns a constant value * Creates a LongValuesSource that always returns a constant value
*/ */
public static LongValuesSource constant(long value) { public static LongValuesSource constant(long value) {
return new LongValuesSource() { return new ConstantLongValuesSource(value);
@Override }
public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
return new LongValues() {
@Override
public long longValue() throws IOException {
return value;
}
@Override private static class ConstantLongValuesSource extends LongValuesSource {
public boolean advanceExact(int doc) throws IOException {
return true; private final long value;
}
}; private ConstantLongValuesSource(long value) {
} this.value = value;
}
@Override
public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
return new LongValues() {
@Override
public long longValue() throws IOException {
return value;
}
@Override
public boolean advanceExact(int doc) throws IOException {
return true;
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConstantLongValuesSource that = (ConstantLongValuesSource) o;
return value == that.value;
}
@Override
public String toString() {
return "constant(" + value + ")";
}
@Override
public boolean needsScores() {
return false;
}
};
} }
private static class FieldValuesSource extends LongValuesSource { private static class FieldValuesSource extends LongValuesSource {
@ -117,6 +154,11 @@ public abstract class LongValuesSource {
return Objects.equals(field, that.field); return Objects.equals(field, that.field);
} }
@Override
public String toString() {
return "long(" + field + ")";
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(field); return Objects.hash(field);

View File

@ -92,6 +92,14 @@ public class TestDoubleValuesSource extends LuceneTestCase {
assertEquals(vs1.hashCode(), vs2.hashCode()); assertEquals(vs1.hashCode(), vs2.hashCode());
DoubleValuesSource v3 = DoubleValuesSource.fromLongField("long"); DoubleValuesSource v3 = DoubleValuesSource.fromLongField("long");
assertFalse(vs1.equals(v3)); assertFalse(vs1.equals(v3));
assertEquals(DoubleValuesSource.constant(5), DoubleValuesSource.constant(5));
assertEquals(DoubleValuesSource.constant(5).hashCode(), DoubleValuesSource.constant(5).hashCode());
assertFalse((DoubleValuesSource.constant(5).equals(DoubleValuesSource.constant(6))));
assertEquals(DoubleValuesSource.SCORES, DoubleValuesSource.SCORES);
assertFalse(DoubleValuesSource.constant(5).equals(DoubleValuesSource.SCORES));
} }
public void testSimpleFieldSortables() throws Exception { public void testSimpleFieldSortables() throws Exception {
@ -184,13 +192,6 @@ public class TestDoubleValuesSource extends LuceneTestCase {
testExplanations(q, DoubleValuesSource.fromDoubleField("double")); testExplanations(q, DoubleValuesSource.fromDoubleField("double"));
testExplanations(q, DoubleValuesSource.fromDoubleField("onefield")); testExplanations(q, DoubleValuesSource.fromDoubleField("onefield"));
testExplanations(q, DoubleValuesSource.constant(5.45)); testExplanations(q, DoubleValuesSource.constant(5.45));
testExplanations(q, DoubleValuesSource.function(
DoubleValuesSource.fromDoubleField("double"), "v * 4 + 73",
v -> v * 4 + 73
));
testExplanations(q, DoubleValuesSource.scoringFunction(
DoubleValuesSource.fromDoubleField("double"), "v * score", (v, s) -> v * s
));
} }
} }
@ -227,4 +228,5 @@ public class TestDoubleValuesSource extends LuceneTestCase {
} }
}); });
} }
} }

View File

@ -706,6 +706,51 @@ public class TestRangeFacetCounts extends FacetTestCase {
} }
private static class PlusOneValuesSource extends DoubleValuesSource {
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
return new DoubleValues() {
int doc = -1;
@Override
public double doubleValue() throws IOException {
return doc + 1;
}
@Override
public boolean advanceExact(int doc) throws IOException {
this.doc = doc;
return true;
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException {
return Explanation.match(docId + 1, "");
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return obj.getClass() == PlusOneValuesSource.class;
}
@Override
public String toString() {
return null;
}
}
public void testCustomDoubleValuesSource() throws Exception { public void testCustomDoubleValuesSource() throws Exception {
Directory dir = newDirectory(); Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir); RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
@ -718,35 +763,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
// Test wants 3 docs in one segment: // Test wants 3 docs in one segment:
writer.forceMerge(1); writer.forceMerge(1);
final DoubleValuesSource vs = new DoubleValuesSource() { final DoubleValuesSource vs = new PlusOneValuesSource();
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
return new DoubleValues() {
int doc = -1;
@Override
public double doubleValue() throws IOException {
return doc + 1;
}
@Override
public boolean advanceExact(int doc) throws IOException {
this.doc = doc;
return true;
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException {
return Explanation.match(docId + 1, "");
}
};
FacetsConfig config = new FacetsConfig(); FacetsConfig config = new FacetsConfig();

View File

@ -121,15 +121,6 @@ public final class FunctionScoreQuery extends Query {
Explanation.match(boost, "boost"), expl); Explanation.match(boost, "boost"), expl);
} }
private Explanation scoreExplanation(LeafReaderContext context, int doc, DoubleValues scores) throws IOException {
if (valueSource.needsScores() == false)
return Explanation.match((float) scores.doubleValue(), valueSource.toString());
float score = (float) scores.doubleValue();
return Explanation.match(score, "computed from:",
Explanation.match(score, valueSource.toString()),
inner.explain(context, doc));
}
@Override @Override
public Scorer scorer(LeafReaderContext context) throws IOException { public Scorer scorer(LeafReaderContext context) throws IOException {
Scorer in = inner.scorer(context); Scorer in = inner.scorer(context);

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DocIdSetIterator;
@ -120,85 +121,141 @@ public abstract class ValueSource {
* Expose this ValueSource as a LongValuesSource * Expose this ValueSource as a LongValuesSource
*/ */
public LongValuesSource asLongValuesSource() { public LongValuesSource asLongValuesSource() {
return new LongValuesSource() { return new WrappedLongValuesSource(this);
@Override }
public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
Map context = new IdentityHashMap<>();
FakeScorer scorer = new FakeScorer();
context.put("scorer", scorer);
final FunctionValues fv = ValueSource.this.getValues(context, ctx);
return new LongValues() {
@Override private static class WrappedLongValuesSource extends LongValuesSource {
public long longValue() throws IOException {
return fv.longVal(scorer.current);
}
@Override private final ValueSource in;
public boolean advanceExact(int doc) throws IOException {
scorer.current = doc; private WrappedLongValuesSource(ValueSource in) {
if (scores != null && scores.advanceExact(doc)) this.in = in;
scorer.score = (float) scores.doubleValue(); }
else
scorer.score = 0; @Override
return fv.exists(doc); public LongValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
} Map context = new IdentityHashMap<>();
}; FakeScorer scorer = new FakeScorer();
} context.put("scorer", scorer);
final FunctionValues fv = in.getValues(context, ctx);
return new LongValues() {
@Override
public long longValue() throws IOException {
return fv.longVal(scorer.current);
}
@Override
public boolean advanceExact(int doc) throws IOException {
scorer.current = doc;
if (scores != null && scores.advanceExact(doc))
scorer.score = (float) scores.doubleValue();
else
scorer.score = 0;
return fv.exists(doc);
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WrappedLongValuesSource that = (WrappedLongValuesSource) o;
return Objects.equals(in, that.in);
}
@Override
public int hashCode() {
return Objects.hash(in);
}
@Override
public String toString() {
return in.toString();
}
@Override
public boolean needsScores() {
return false;
}
};
} }
/** /**
* Expose this ValueSource as a DoubleValuesSource * Expose this ValueSource as a DoubleValuesSource
*/ */
public DoubleValuesSource asDoubleValuesSource() { public DoubleValuesSource asDoubleValuesSource() {
return new DoubleValuesSource() { return new WrappedDoubleValuesSource(this);
@Override }
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
Map context = new HashMap<>();
FakeScorer scorer = new FakeScorer();
context.put("scorer", scorer);
FunctionValues fv = ValueSource.this.getValues(context, ctx);
return new DoubleValues() {
@Override private static class WrappedDoubleValuesSource extends DoubleValuesSource {
public double doubleValue() throws IOException {
return fv.doubleVal(scorer.current); private final ValueSource in;
private WrappedDoubleValuesSource(ValueSource in) {
this.in = in;
}
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
Map context = new HashMap<>();
FakeScorer scorer = new FakeScorer();
context.put("scorer", scorer);
FunctionValues fv = in.getValues(context, ctx);
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return fv.doubleVal(scorer.current);
}
@Override
public boolean advanceExact(int doc) throws IOException {
scorer.current = doc;
if (scores != null && scores.advanceExact(doc)) {
scorer.score = (float) scores.doubleValue();
} }
else
scorer.score = 0;
return fv.exists(doc);
}
};
}
@Override @Override
public boolean advanceExact(int doc) throws IOException { public boolean needsScores() {
scorer.current = doc; return true; // be on the safe side
if (scores != null && scores.advanceExact(doc)) { }
scorer.score = (float) scores.doubleValue();
}
else
scorer.score = 0;
return fv.exists(doc);
}
};
}
@Override @Override
public boolean needsScores() { public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException {
return true; // be on the safe side Map context = new HashMap<>();
} FakeScorer scorer = new FakeScorer();
scorer.score = scoreExplanation.getValue();
context.put("scorer", scorer);
FunctionValues fv = in.getValues(context, ctx);
return fv.explain(docId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WrappedDoubleValuesSource that = (WrappedDoubleValuesSource) o;
return Objects.equals(in, that.in);
}
@Override
public int hashCode() {
return Objects.hash(in);
}
@Override
public String toString() {
return in.toString();
}
@Override
public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreExplanation) throws IOException {
Map context = new HashMap<>();
FakeScorer scorer = new FakeScorer();
scorer.score = scoreExplanation.getValue();
context.put("scorer", scorer);
FunctionValues fv = ValueSource.this.getValues(context, ctx);
return fv.explain(docId);
}
};
} }
// //

View File

@ -59,19 +59,15 @@ public class TestFunctionScoreExplanations extends BaseExplanationTestCase {
public void testExplanationsIncludingScore() throws Exception { public void testExplanationsIncludingScore() throws Exception {
DoubleValuesSource scores = DoubleValuesSource.function(DoubleValuesSource.SCORES, "v * 2", v -> v * 2);
Query q = new TermQuery(new Term(FIELD, "w1")); Query q = new TermQuery(new Term(FIELD, "w1"));
FunctionScoreQuery csq = new FunctionScoreQuery(q, scores); FunctionScoreQuery csq = new FunctionScoreQuery(q, DoubleValuesSource.SCORES);
qtest(csq, new int[] { 0, 1, 2, 3 }); qtest(csq, new int[] { 0, 1, 2, 3 });
Explanation e1 = searcher.explain(q, 0); Explanation e1 = searcher.explain(q, 0);
Explanation e = searcher.explain(csq, 0); Explanation e = searcher.explain(csq, 0);
assertEquals(e.getDetails().length, 2); assertEquals(e, e1);
assertEquals(e1.getValue() * 2, e.getValue(), 0.00001);
} }
public void testSubExplanations() throws IOException { public void testSubExplanations() throws IOException {

View File

@ -17,12 +17,18 @@
package org.apache.lucene.queries.function; package org.apache.lucene.queries.function;
import java.io.IOException;
import java.util.function.DoubleUnaryOperator;
import java.util.function.ToDoubleBiFunction;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DoubleValues;
import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.DoubleValuesSource;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
@ -70,7 +76,7 @@ public class TestFunctionScoreQuery extends FunctionTestSetup {
public void testScoreModifyingSource() throws Exception { public void testScoreModifyingSource() throws Exception {
DoubleValuesSource iii = DoubleValuesSource.fromIntField("iii"); DoubleValuesSource iii = DoubleValuesSource.fromIntField("iii");
DoubleValuesSource score = DoubleValuesSource.scoringFunction(iii, "v * s", (v, s) -> v * s); DoubleValuesSource score = scoringFunction(iii, (v, s) -> v * s);
BooleanQuery bq = new BooleanQuery.Builder() BooleanQuery bq = new BooleanQuery.Builder()
.add(new TermQuery(new Term(TEXT_FIELD, "first")), BooleanClause.Occur.SHOULD) .add(new TermQuery(new Term(TEXT_FIELD, "first")), BooleanClause.Occur.SHOULD)
@ -95,8 +101,7 @@ public class TestFunctionScoreQuery extends FunctionTestSetup {
// check boosts with non-distributive score source // check boosts with non-distributive score source
public void testBoostsAreAppliedLast() throws Exception { public void testBoostsAreAppliedLast() throws Exception {
DoubleValuesSource scores DoubleValuesSource scores = function(DoubleValuesSource.SCORES, v -> Math.log(v + 4));
= DoubleValuesSource.function(DoubleValuesSource.SCORES, "ln(v + 4)", v -> Math.log(v + 4));
Query q1 = new FunctionScoreQuery(new TermQuery(new Term(TEXT_FIELD, "text")), scores); Query q1 = new FunctionScoreQuery(new TermQuery(new Term(TEXT_FIELD, "text")), scores);
TopDocs plain = searcher.search(q1, 5); TopDocs plain = searcher.search(q1, 5);
@ -111,4 +116,84 @@ public class TestFunctionScoreQuery extends FunctionTestSetup {
} }
public static DoubleValuesSource function(DoubleValuesSource in, DoubleUnaryOperator function) {
return new DoubleValuesSource() {
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
DoubleValues v = in.getValues(ctx, scores);
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return function.applyAsDouble(v.doubleValue());
}
@Override
public boolean advanceExact(int doc) throws IOException {
return v.advanceExact(doc);
}
};
}
@Override
public boolean needsScores() {
return in.needsScores();
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return false;
}
@Override
public String toString() {
return "fn";
}
};
}
private static DoubleValuesSource scoringFunction(DoubleValuesSource in, ToDoubleBiFunction<Double, Double> function) {
return new DoubleValuesSource() {
@Override
public DoubleValues getValues(LeafReaderContext ctx, DoubleValues scores) throws IOException {
DoubleValues v = in.getValues(ctx, scores);
return new DoubleValues() {
@Override
public double doubleValue() throws IOException {
return function.applyAsDouble(v.doubleValue(), scores.doubleValue());
}
@Override
public boolean advanceExact(int doc) throws IOException {
return v.advanceExact(doc);
}
};
}
@Override
public boolean needsScores() {
return true;
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return false;
}
@Override
public String toString() {
return "fn";
}
};
}
} }

View File

@ -171,6 +171,21 @@ public class DocumentValueSourceDictionaryTest extends LuceneTestCase {
public boolean needsScores() { public boolean needsScores() {
return false; return false;
} }
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return false;
}
@Override
public String toString() {
return null;
}
}; };
} }