You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2015/08/06 19:47:25 UTC
svn commit: r1694543 - in /lucene/dev/trunk: lucene/
lucene/queries/src/java/org/apache/lucene/queries/function/
lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/
lucene/queries/src/java/org/apache/lucene/queries/function/valuesourc...
Author: dsmiley
Date: Thu Aug 6 17:47:24 2015
New Revision: 1694543
URL: http://svn.apache.org/r1694543
Log:
LUCENE-6720: new FunctionRangeQuery wrapper around ValueSourceScorer.
And ValueSourceScorer improvements.
Added:
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java (with props)
lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionRangeQuery.java (with props)
Removed:
lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/util/ValueSourceFilter.java
Modified:
lucene/dev/trunk/lucene/CHANGES.txt
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DoubleDocValues.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/IntDocValues.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/LongDocValues.java
lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/EnumFieldSource.java
lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java
lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/FunctionRangeQuery.java
Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Thu Aug 6 17:47:24 2015
@@ -45,11 +45,19 @@ API Changes
======================= Lucene 5.4.0 =======================
+New Features
+
+* LUCENE-6720: New FunctionRangeQuery wrapper around ValueSourceScorer
+ (returned from ValueSource/FunctionValues.getRangeScorer()). (David Smiley)
+
Optimizations
* LUCENE-6708: TopFieldCollector does not compute the score several times on the
same document anymore. (Adrien Grand)
+* LUCENE-6720: ValueSourceScorer, returned from
+ FunctionValues.getRangeScorer(), now uses TwoPhaseIterator. (David Smiley)
+
======================= Lucene 5.3.0 =======================
New Features
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java Thu Aug 6 17:47:24 2015
@@ -29,16 +29,14 @@ import org.apache.lucene.search.IndexSea
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight;
-import org.apache.lucene.util.Bits;
/**
* Returns a score for each document based on a ValueSource,
* often some function of the value of a field.
*
- * <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
- *
- *
+ * @see ValueSourceScorer
+ * @lucene.experimental
*/
public class FunctionQuery extends Query {
final ValueSource func;
Added: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java?rev=1694543&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java (added)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java Thu Aug 6 17:47:24 2015
@@ -0,0 +1,149 @@
+package org.apache.lucene.queries.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 java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Weight;
+
+/**
+ * A Query wrapping a {@link ValueSource} that matches docs in which the values in the value source match a configured
+ * range. The score is the float value. This can be a slow query if run by itself since it must visit all docs;
+ * ideally it's combined with other queries.
+ * It's mostly a wrapper around
+ * {@link FunctionValues#getRangeScorer(IndexReader, String, String, boolean, boolean)}.
+ *
+ * A similar class is {@code org.apache.lucene.search.DocValuesRangeQuery} in the sandbox module. That one is
+ * constant scoring.
+ *
+ * @see FunctionQuery (constant scoring)
+ * @lucene.experimental
+ */
+public class FunctionRangeQuery extends Query {
+
+ private final ValueSource valueSource;
+
+ // These two are declared as strings because FunctionValues.getRangeScorer takes String args and parses them.
+ private final String lowerVal;
+ private final String upperVal;
+ private final boolean includeLower;
+ private final boolean includeUpper;
+
+ public FunctionRangeQuery(ValueSource valueSource, Number lowerVal, Number upperVal,
+ boolean includeLower, boolean includeUpper) {
+ this(valueSource, lowerVal == null ? null : lowerVal.toString(), upperVal == null ? null : upperVal.toString(),
+ includeLower, includeUpper);
+ }
+
+ public FunctionRangeQuery(ValueSource valueSource, String lowerVal, String upperVal,
+ boolean includeLower, boolean includeUpper) {
+ this.valueSource = valueSource;
+ this.lowerVal = lowerVal;
+ this.upperVal = upperVal;
+ this.includeLower = includeLower;
+ this.includeUpper = includeUpper;
+ }
+
+ @Override
+ public String toString(String field) {
+ return "frange(" + valueSource + "):"
+ + (includeLower ? '[' : '{')
+ + (lowerVal == null ? "*" : lowerVal) + " TO " + (upperVal == null ? "*" : upperVal)
+ + (includeUpper ? ']' : '}');
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof FunctionRangeQuery)) return false;
+ if (!super.equals(o)) return false;
+ FunctionRangeQuery that = (FunctionRangeQuery) o;
+ return Objects.equals(includeLower, that.includeLower) &&
+ Objects.equals(includeUpper, that.includeUpper) &&
+ Objects.equals(valueSource, that.valueSource) &&
+ Objects.equals(lowerVal, that.lowerVal) &&
+ Objects.equals(upperVal, that.upperVal);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), valueSource, lowerVal, upperVal, includeLower, includeUpper);
+ }
+
+ @Override
+ public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+ return new FunctionRangeWeight(searcher);
+ }
+
+ private class FunctionRangeWeight extends Weight {
+ @SuppressWarnings("rawtypes")
+ private final Map vsContext;
+
+ public FunctionRangeWeight(IndexSearcher searcher) throws IOException {
+ super(FunctionRangeQuery.this);
+ vsContext = ValueSource.newContext(searcher);
+ valueSource.createWeight(vsContext, searcher);//callback on valueSource tree
+ }
+
+ @Override
+ public void extractTerms(Set<Term> terms) {
+ //none
+ }
+
+ //Note: this uses the functionValue's floatVal() as the score; queryNorm/boost is ignored.
+ @Override
+ public float getValueForNormalization() throws IOException {
+ return 1f;
+ }
+
+ @Override
+ public void normalize(float norm, float topLevelBoost) {
+ //no-op
+ }
+
+ @Override
+ public Explanation explain(LeafReaderContext context, int doc) throws IOException {
+ FunctionValues functionValues = valueSource.getValues(vsContext, context);
+ //note: by using ValueSourceScorer directly, we avoid calling scorer.advance(doc) and checking if true,
+ // which can be slow since if that doc doesn't match, it has to linearly find the next matching
+ ValueSourceScorer scorer = scorer(context);
+ if (scorer.matches(doc)) {
+ scorer.advance(doc);
+ return Explanation.match(scorer.score(), FunctionRangeQuery.this.toString(), functionValues.explain(doc));
+ } else {
+ return Explanation.noMatch(FunctionRangeQuery.this.toString(), functionValues.explain(doc));
+ }
+ }
+
+ @Override
+ public ValueSourceScorer scorer(LeafReaderContext context) throws IOException {
+ FunctionValues functionValues = valueSource.getValues(vsContext, context);
+ // getRangeScorer takes String args and parses them. Weird.
+ return functionValues.getRangeScorer(context.reader(), lowerVal, upperVal, includeLower, includeUpper);
+ }
+ }
+}
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java Thu Aug 6 17:47:24 2015
@@ -17,8 +17,9 @@ package org.apache.lucene.queries.functi
* limitations under the License.
*/
-import org.apache.lucene.search.*;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Scorer;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.mutable.MutableValue;
import org.apache.lucene.util.mutable.MutableValueFloat;
@@ -136,10 +137,23 @@ public abstract class FunctionValues {
return Explanation.match(floatVal(doc), toString(doc));
}
+ /**
+ * Yields a {@link Scorer} that matches all documents,
+ * and that which produces scores equal to {@link #floatVal(int)}.
+ */
public ValueSourceScorer getScorer(IndexReader reader) {
- return new ValueSourceScorer(reader, this);
+ return new ValueSourceScorer(reader, this) {
+ @Override
+ public boolean matches(int doc) {
+ return true;
+ }
+ };
}
+ /**
+ * Yields a {@link Scorer} that matches documents with values between the specified range,
+ * and that which produces scores equal to {@link #floatVal(int)}.
+ */
// A RangeValueSource can't easily be a ValueSource that takes another ValueSource
// because it needs different behavior depending on the type of fields. There is also
// a setup cost - parsing and normalizing params, and doing a binary search on the StringIndex.
@@ -165,7 +179,7 @@ public abstract class FunctionValues {
if (includeLower && includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
float docVal = floatVal(doc);
return docVal >= l && docVal <= u;
}
@@ -174,7 +188,7 @@ public abstract class FunctionValues {
else if (includeLower && !includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
float docVal = floatVal(doc);
return docVal >= l && docVal < u;
}
@@ -183,7 +197,7 @@ public abstract class FunctionValues {
else if (!includeLower && includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
float docVal = floatVal(doc);
return docVal > l && docVal <= u;
}
@@ -192,7 +206,7 @@ public abstract class FunctionValues {
else {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
float docVal = floatVal(doc);
return docVal > l && docVal < u;
}
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java Thu Aug 6 17:47:24 2015
@@ -20,71 +20,74 @@ package org.apache.lucene.queries.functi
import java.io.IOException;
import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
+import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Scorer;
-import org.apache.lucene.util.Bits;
+import org.apache.lucene.search.TwoPhaseIterator;
/**
* {@link Scorer} which returns the result of {@link FunctionValues#floatVal(int)} as
- * the score for a document.
+ * the score for a document, and which filters out documents that don't match {@link #matches(int)}.
+ * This Scorer has a {@link TwoPhaseIterator}. This is similar to {@link FunctionQuery},
+ * but this one has no {@link org.apache.lucene.search.Weight} normalization factors/multipliers
+ * and that one doesn't filter either.
+ * <p>
+ * Note: If the scores are needed, then the underlying value will probably be
+ * fetched/computed twice -- once to filter and next to return the score. If that's non-trivial then
+ * consider wrapping it in an implementation that will cache the current value.
+ * </p>
+ *
+ * @see FunctionQuery
+ * @lucene.experimental
*/
-public class ValueSourceScorer extends Scorer {
- protected final IndexReader reader;
- private int doc = -1;
- protected final int maxDoc;
+public abstract class ValueSourceScorer extends Scorer {
protected final FunctionValues values;
- protected boolean checkDeletes;
- private final Bits liveDocs;
+ private final TwoPhaseIterator twoPhaseIterator;
+ private final DocIdSetIterator disi;
+ //TODO use LeafReaderContext not IndexReader?
protected ValueSourceScorer(IndexReader reader, FunctionValues values) {
- super(null);
- this.reader = reader;
- this.maxDoc = reader.maxDoc();
+ super(null);//no weight
this.values = values;
- setCheckDeletes(true);
- this.liveDocs = MultiFields.getLiveDocs(reader);
+ this.twoPhaseIterator = new TwoPhaseIterator(DocIdSetIterator.all(reader.maxDoc())) { // no approximation!
+ @Override
+ public boolean matches() throws IOException {
+ return ValueSourceScorer.this.matches(docID());
+ }
+ };
+ this.disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseIterator);
}
- public IndexReader getReader() {
- return reader;
- }
-
- public void setCheckDeletes(boolean checkDeletes) {
- this.checkDeletes = checkDeletes && reader.hasDeletions();
- }
+ /** Override to decide if this document matches. It's called by {@link TwoPhaseIterator#matches()}. */
+ public abstract boolean matches(int doc);
- public boolean matches(int doc) {
- return (!checkDeletes || liveDocs.get(doc)) && matchesValue(doc);
- }
-
- public boolean matchesValue(int doc) {
- return true;
+ @Override
+ public TwoPhaseIterator asTwoPhaseIterator() {
+ return twoPhaseIterator;
}
@Override
public int docID() {
- return doc;
+ return disi.docID();
}
@Override
public int nextDoc() throws IOException {
- for (; ;) {
- doc++;
- if (doc >= maxDoc) return doc = NO_MORE_DOCS;
- if (matches(doc)) return doc;
- }
+ return disi.nextDoc();
}
@Override
public int advance(int target) throws IOException {
- // also works fine when target==NO_MORE_DOCS
- doc = target - 1;
- return nextDoc();
+ return disi.advance(target);
}
@Override
public float score() throws IOException {
- return values.floatVal(doc);
+ // (same as FunctionQuery, but no qWeight) TODO consider adding configurable qWeight
+ float score = values.floatVal(disi.docID());
+ // Current Lucene priority queues can't handle NaN and -Infinity, so
+ // map to -Float.MAX_VALUE. This conditional handles both -infinity
+ // and NaN since comparisons with NaN are always false.
+ return score > Float.NEGATIVE_INFINITY ? score : -Float.MAX_VALUE;
}
@Override
@@ -94,6 +97,6 @@ public class ValueSourceScorer extends S
@Override
public long cost() {
- return maxDoc;
+ return disi.cost();
}
}
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java Thu Aug 6 17:47:24 2015
@@ -19,9 +19,9 @@ package org.apache.lucene.queries.functi
import java.io.IOException;
-import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
@@ -124,7 +124,7 @@ public abstract class DocTermsIndexDocVa
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
int ord = termsIndex.getOrd(doc);
return ord >= ll && ord <= uu;
}
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DoubleDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DoubleDocValues.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DoubleDocValues.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DoubleDocValues.java Thu Aug 6 17:47:24 2015
@@ -106,7 +106,7 @@ public abstract class DoubleDocValues ex
if (includeLower && includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
double docVal = doubleVal(doc);
return docVal >= l && docVal <= u;
}
@@ -115,7 +115,7 @@ public abstract class DoubleDocValues ex
else if (includeLower && !includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
double docVal = doubleVal(doc);
return docVal >= l && docVal < u;
}
@@ -124,7 +124,7 @@ public abstract class DoubleDocValues ex
else if (!includeLower && includeUpper) {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
double docVal = doubleVal(doc);
return docVal > l && docVal <= u;
}
@@ -133,7 +133,7 @@ public abstract class DoubleDocValues ex
else {
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
double docVal = doubleVal(doc);
return docVal > l && docVal < u;
}
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/IntDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/IntDocValues.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/IntDocValues.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/IntDocValues.java Thu Aug 6 17:47:24 2015
@@ -103,7 +103,7 @@ public abstract class IntDocValues exten
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
int val = intVal(doc);
// only check for deleted if it's the default value
// if (val==0 && reader.isDeleted(doc)) return false;
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/LongDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/LongDocValues.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/LongDocValues.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/LongDocValues.java Thu Aug 6 17:47:24 2015
@@ -112,7 +112,7 @@ public abstract class LongDocValues exte
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
long val = longVal(doc);
// only check for deleted if it's the default value
// if (val==0 && reader.isDeleted(doc)) return false;
Modified: lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/EnumFieldSource.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/EnumFieldSource.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/EnumFieldSource.java (original)
+++ lucene/dev/trunk/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/EnumFieldSource.java Thu Aug 6 17:47:24 2015
@@ -20,9 +20,9 @@ package org.apache.lucene.queries.functi
import java.io.IOException;
import java.util.Map;
-import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSourceScorer;
@@ -143,7 +143,7 @@ public class EnumFieldSource extends Fie
return new ValueSourceScorer(reader, this) {
@Override
- public boolean matchesValue(int doc) {
+ public boolean matches(int doc) {
int val = intVal(doc);
// only check for deleted if it's the default value
// if (val==0 && reader.isDeleted(doc)) return false;
Modified: lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java (original)
+++ lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java Thu Aug 6 17:47:24 2015
@@ -20,6 +20,7 @@ package org.apache.lucene.queries.functi
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryUtils;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
@@ -59,7 +60,7 @@ public class TestFieldScoreQuery extends
// Test that FieldScoreQuery returns docs in expected order.
private void doTestRank (ValueSource valueSource) throws Exception {
- FunctionQuery functionQuery = new FunctionQuery(valueSource);
+ Query functionQuery = getFunctionQuery(valueSource);
IndexReader r = DirectoryReader.open(dir);
IndexSearcher s = newSearcher(r);
log("test: "+ functionQuery);
@@ -92,7 +93,7 @@ public class TestFieldScoreQuery extends
// Test that FieldScoreQuery returns docs with expected score.
private void doTestExactScore (ValueSource valueSource) throws Exception {
- FunctionQuery functionQuery = new FunctionQuery(valueSource);
+ Query functionQuery = getFunctionQuery(valueSource);
IndexReader r = DirectoryReader.open(dir);
IndexSearcher s = newSearcher(r);
TopDocs td = s.search(functionQuery,1000);
@@ -108,4 +109,14 @@ public class TestFieldScoreQuery extends
r.close();
}
+ protected Query getFunctionQuery(ValueSource valueSource) {
+ if (random().nextBoolean()) {
+ return new FunctionQuery(valueSource);
+ } else {
+ Integer lower = (random().nextBoolean() ? null : 1);//1 is the lowest value
+ Integer upper = (random().nextBoolean() ? null : N_DOCS); // N_DOCS is the highest value
+ return new FunctionRangeQuery(valueSource, lower, upper, true, true);//will match all docs based on the indexed data
+ }
+ }
+
}
Added: lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionRangeQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionRangeQuery.java?rev=1694543&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionRangeQuery.java (added)
+++ lucene/dev/trunk/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionRangeQuery.java Thu Aug 6 17:47:24 2015
@@ -0,0 +1,114 @@
+package org.apache.lucene.queries.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 java.io.IOException;
+
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TopDocs;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestFunctionRangeQuery extends FunctionTestSetup {
+
+ IndexReader indexReader;
+ IndexSearcher indexSearcher;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ createIndex(true);//doMultiSegment
+ }
+
+ @Before
+ protected void before() throws IOException {
+ indexReader = DirectoryReader.open(dir);
+ indexSearcher = newSearcher(indexReader);
+ }
+
+ @After
+ public void after() throws IOException {
+ indexReader.close();
+ }
+
+ @Test
+ public void testRangeInt() throws IOException {
+ doTestRange(INT_VALUESOURCE);
+ }
+
+ @Test
+ public void testRangeFloat() throws IOException {
+ doTestRange(FLOAT_VALUESOURCE);
+ }
+
+ private void doTestRange(ValueSource valueSource) throws IOException {
+ Query rangeQuery = new FunctionRangeQuery(valueSource, 2, 4, true, false);
+ ScoreDoc[] scoreDocs = indexSearcher.search(rangeQuery, N_DOCS).scoreDocs;
+ expectScores(scoreDocs, 3, 2);
+
+ rangeQuery = new FunctionRangeQuery(valueSource, 2, 4, false, true);
+ scoreDocs = indexSearcher.search(rangeQuery, N_DOCS).scoreDocs;
+ expectScores(scoreDocs, 4, 3);
+ }
+
+ @Test
+ public void testDeleted() throws IOException {
+ // We delete doc with #3. Note we don't commit it to disk; we search using a near eal-time reader.
+ final ValueSource valueSource = INT_VALUESOURCE;
+ IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(null));
+ try {
+ writer.deleteDocuments(new FunctionRangeQuery(valueSource, 3, 3, true, true));//delete the one with #3
+ assert writer.hasDeletions();
+ try (IndexReader indexReader2 = DirectoryReader.open(writer, true)) {//applyAllDeletes
+ IndexSearcher indexSearcher2 = new IndexSearcher(indexReader2);
+ TopDocs topDocs = indexSearcher2.search(new FunctionRangeQuery(valueSource, 3, 4, true, true), N_DOCS);
+ expectScores(topDocs.scoreDocs, 4);//missing #3 because it's deleted
+ }
+ } finally {
+ writer.rollback();
+ writer.close();
+ }
+ }
+
+ @Test
+ public void testExplain() throws IOException {
+ Query rangeQuery = new FunctionRangeQuery(INT_VALUESOURCE, 2, 2, true, true);
+ ScoreDoc[] scoreDocs = indexSearcher.search(rangeQuery, N_DOCS).scoreDocs;
+ Explanation explain = indexSearcher.explain(rangeQuery, scoreDocs[0].doc);
+ // Just validate it looks reasonable
+ assertEquals(
+ "2.0 = frange(int(" + INT_FIELD + ")):[2 TO 2]\n" +
+ " 2.0 = int(" + INT_FIELD + ")=2\n",
+ explain.toString());
+ }
+
+ private void expectScores(ScoreDoc[] scoreDocs, int... docScores) {
+ assertEquals(docScores.length, scoreDocs.length);
+ for (int i = 0; i < docScores.length; i++) {
+ assertEquals(docScores[i], scoreDocs[i].score, 0.0);
+ }
+ }
+}
Modified: lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java Thu Aug 6 17:47:24 2015
@@ -25,7 +25,7 @@ import com.spatial4j.core.shape.Shape;
import org.apache.lucene.document.DoubleField;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
-import org.apache.lucene.queries.function.FunctionQuery;
+import org.apache.lucene.queries.function.FunctionRangeQuery;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
@@ -38,8 +38,6 @@ import org.apache.lucene.spatial.Spatial
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
-import org.apache.lucene.spatial.util.CachingDoubleValueSource;
-import org.apache.lucene.spatial.util.ValueSourceFilter;
/**
* Simple {@link SpatialStrategy} which represents Points in two numeric {@link
@@ -150,80 +148,19 @@ public class PointVectorStrategy extends
} else if (shape instanceof Circle) {
Circle circle = (Circle)shape;
Rectangle bbox = circle.getBoundingBox();
- ValueSourceFilter vsf = new ValueSourceFilter(
- new QueryWrapperFilter(makeWithin(bbox)),
- makeDistanceValueSource(circle.getCenter()),
- 0,
- circle.getRadius() );
- return new ConstantScoreQuery(vsf);
+ Query approxQuery = makeWithin(bbox);
+ BooleanQuery.Builder bqBuilder = new BooleanQuery.Builder();
+ FunctionRangeQuery vsRangeQuery =
+ new FunctionRangeQuery(makeDistanceValueSource(circle.getCenter()), 0.0, circle.getRadius(), true, true);
+ bqBuilder.add(approxQuery, BooleanClause.Occur.FILTER);//should have lowest "cost" value; will drive iteration
+ bqBuilder.add(vsRangeQuery, BooleanClause.Occur.FILTER);
+ return new ConstantScoreQuery(bqBuilder.build());
} else {
throw new UnsupportedOperationException("Only Rectangles and Circles are currently supported, " +
"found [" + shape.getClass() + "]");//TODO
}
}
- //TODO this is basically old code that hasn't been verified well and should probably be removed
- public Query makeQueryDistanceScore(SpatialArgs args) {
- // For starters, just limit the bbox
- Shape shape = args.getShape();
- if (!(shape instanceof Rectangle || shape instanceof Circle)) {
- throw new UnsupportedOperationException("Only Rectangles and Circles are currently supported, " +
- "found [" + shape.getClass() + "]");//TODO
- }
-
- Rectangle bbox = shape.getBoundingBox();
-
- if (bbox.getCrossesDateLine()) {
- throw new UnsupportedOperationException( "Crossing dateline not yet supported" );
- }
-
- ValueSource valueSource = null;
-
- Query spatial = null;
- SpatialOperation op = args.getOperation();
-
- if( SpatialOperation.is( op,
- SpatialOperation.BBoxWithin,
- SpatialOperation.BBoxIntersects ) ) {
- spatial = makeWithin(bbox);
- }
- else if( SpatialOperation.is( op,
- SpatialOperation.Intersects,
- SpatialOperation.IsWithin ) ) {
- spatial = makeWithin(bbox);
- if( args.getShape() instanceof Circle) {
- Circle circle = (Circle)args.getShape();
-
- // Make the ValueSource
- valueSource = makeDistanceValueSource(shape.getCenter());
-
- ValueSourceFilter vsf = new ValueSourceFilter(
- new QueryWrapperFilter( spatial ), valueSource, 0, circle.getRadius() );
-
- spatial = vsf;
- }
- }
- else if( op == SpatialOperation.IsDisjointTo ) {
- spatial = makeDisjoint(bbox);
- }
-
- if( spatial == null ) {
- throw new UnsupportedSpatialOperation(args.getOperation());
- }
-
- if( valueSource != null ) {
- valueSource = new CachingDoubleValueSource(valueSource);
- }
- else {
- valueSource = makeDistanceValueSource(shape.getCenter());
- }
- Query spatialRankingQuery = new FunctionQuery(valueSource);
- BooleanQuery.Builder bq = new BooleanQuery.Builder();
- bq.add(spatial,BooleanClause.Occur.MUST);
- bq.add(spatialRankingQuery,BooleanClause.Occur.MUST);
- return bq.build();
- }
-
/**
* Constructs a query to retrieve documents that fully contain the input envelope.
*/
@@ -252,21 +189,6 @@ public class PointVectorStrategy extends
true);//inclusive
}
- /**
- * Constructs a query to retrieve documents that fully contain the input envelope.
- */
- private Query makeDisjoint(Rectangle bbox) {
- if (bbox.getCrossesDateLine())
- throw new UnsupportedOperationException("makeDisjoint doesn't handle dateline cross");
- Query qX = rangeQuery(fieldNameX, bbox.getMinX(), bbox.getMaxX());
- Query qY = rangeQuery(fieldNameY, bbox.getMinY(), bbox.getMaxY());
-
- BooleanQuery.Builder bq = new BooleanQuery.Builder();
- bq.add(qX,BooleanClause.Occur.MUST_NOT);
- bq.add(qY,BooleanClause.Occur.MUST_NOT);
- return bq.build();
- }
-
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/FunctionRangeQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/FunctionRangeQuery.java?rev=1694543&r1=1694542&r2=1694543&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/FunctionRangeQuery.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/FunctionRangeQuery.java Thu Aug 6 17:47:24 2015
@@ -17,6 +17,9 @@
package org.apache.solr.search;
+import java.io.IOException;
+import java.util.Map;
+
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
@@ -24,9 +27,6 @@ import org.apache.lucene.queries.functio
import org.apache.lucene.search.IndexSearcher;
import org.apache.solr.search.function.ValueSourceRangeFilter;
-import java.io.IOException;
-import java.util.Map;
-
// This class works as either a normal constant score query, or as a PostFilter using a collector
public class FunctionRangeQuery extends SolrConstantScoreQuery implements PostFilter {
final ValueSourceRangeFilter rangeFilt;
@@ -53,7 +53,8 @@ public class FunctionRangeQuery extends
@Override
public void collect(int doc) throws IOException {
- if (doc<maxdoc && scorer.matches(doc)) {
+ assert doc < maxdoc;
+ if (scorer.matches(doc)) {
leafDelegate.collect(doc);
}
}