You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2017/01/20 13:46:13 UTC
lucene-solr:branch_6x: LUCENE-7643: Move IndexOrDocValuesQuery to
core.
Repository: lucene-solr
Updated Branches:
refs/heads/branch_6x 3ef9f0e39 -> 20b7dfae4
LUCENE-7643: Move IndexOrDocValuesQuery to core.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/20b7dfae
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/20b7dfae
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/20b7dfae
Branch: refs/heads/branch_6x
Commit: 20b7dfae42810ea4c345355735d732bdbb191150
Parents: 3ef9f0e
Author: Adrien Grand <jp...@gmail.com>
Authored: Thu Jan 19 18:12:04 2017 +0100
Committer: Adrien Grand <jp...@gmail.com>
Committed: Fri Jan 20 14:45:18 2017 +0100
----------------------------------------------------------------------
lucene/CHANGES.txt | 7 +
.../lucene/document/NumericDocValuesField.java | 48 ++++
.../lucene/document/SortedDocValuesField.java | 42 ++++
.../document/SortedNumericDocValuesField.java | 54 +++++
.../SortedNumericDocValuesRangeQuery.java | 150 ++++++++++++
.../document/SortedSetDocValuesField.java | 43 ++++
.../document/SortedSetDocValuesRangeQuery.java | 190 +++++++++++++++
.../lucene/search/IndexOrDocValuesQuery.java | 177 ++++++++++++++
.../lucene/search/TestDocValuesQueries.java | 238 +++++++++++++++++++
.../search/TestIndexOrDocValuesQuery.java | 89 +++++++
.../lucene/search/DocValuesRangeQuery.java | 12 +-
.../lucene/search/IndexOrDocValuesQuery.java | 116 ---------
.../search/TestIndexOrDocValuesQuery.java | 89 -------
.../apache/solr/schema/ICUCollationField.java | 10 +-
.../org/apache/solr/schema/CollationField.java | 3 +-
.../java/org/apache/solr/schema/EnumField.java | 20 +-
.../java/org/apache/solr/schema/FieldType.java | 16 +-
.../java/org/apache/solr/schema/TrieField.java | 45 +++-
18 files changed, 1110 insertions(+), 239 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index ec75b7f..1e00fbc 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -16,6 +16,9 @@ API Changes
* LUCENE-7644: FieldComparatorSource.newComparator() and
SortField.getComparator() no longer throw IOException (Alan Woodward)
+* LUCENE-7643: Replaced doc-values queries in lucene/sandbox with factory
+ methods on the *DocValuesField classes. (Adrien Grand)
+
New Features
* LUCENE-7623: Add FunctionScoreQuery and FunctionMatchQuery (Alan Woodward,
@@ -38,6 +41,10 @@ Improvements
should be run, eg. using points or doc values depending on costs of other
parts of the query. (Adrien Grand)
+* LUCENE-7643: IndexOrDocValuesQuery allows to execute range queries using
+ either points or doc values depending on which one is more efficient.
+ (Adrien Grand)
+
Optimizations
* LUCENE-7641: Optimized point range queries to compute documents that do not
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/NumericDocValuesField.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/NumericDocValuesField.java b/lucene/core/src/java/org/apache/lucene/document/NumericDocValuesField.java
index 5b6dcc8..2651f92 100644
--- a/lucene/core/src/java/org/apache/lucene/document/NumericDocValuesField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/NumericDocValuesField.java
@@ -17,7 +17,15 @@
package org.apache.lucene.document;
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
+import org.apache.lucene.search.Query;
/**
* <p>
@@ -54,4 +62,44 @@ public class NumericDocValuesField extends Field {
super(name, TYPE);
fieldsData = Long.valueOf(value);
}
+
+ /**
+ * Create a range query that matches all documents whose value is between
+ * {@code lowerValue} and {@code upperValue} included.
+ * <p>
+ * You can have half-open ranges (which are in fact </≤ or >/≥ queries)
+ * by setting {@code lowerValue = Long.MIN_VALUE} or {@code upperValue = Long.MAX_VALUE}.
+ * <p>
+ * Ranges are inclusive. For exclusive ranges, pass {@code Math.addExact(lowerValue, 1)}
+ * or {@code Math.addExact(upperValue, -1)}.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link LongPoint#newRangeQuery}.
+ */
+ public static Query newRangeQuery(String field, long lowerValue, long upperValue) {
+ return new SortedNumericDocValuesRangeQuery(field, lowerValue, upperValue) {
+ @Override
+ SortedNumericDocValues getValues(LeafReader reader, String field) throws IOException {
+ NumericDocValues values = reader.getNumericDocValues(field);
+ if (values == null) {
+ return null;
+ }
+ return DocValues.singleton(values, reader.getDocsWithField(field));
+ }
+ };
+ }
+
+ /**
+ * Create a query for matching an exact long value.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link LongPoint#newExactQuery}.
+ */
+ public static Query newExactQuery(String field, long value) {
+ return newRangeQuery(field, value, value);
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/SortedDocValuesField.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedDocValuesField.java b/lucene/core/src/java/org/apache/lucene/document/SortedDocValuesField.java
index bbfb467..feb7725 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedDocValuesField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedDocValuesField.java
@@ -17,7 +17,14 @@
package org.apache.lucene.document;
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
+import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
/**
@@ -59,4 +66,39 @@ public class SortedDocValuesField extends Field {
super(name, TYPE);
fieldsData = bytes;
}
+
+ /**
+ * Create a range query that matches all documents whose value is between
+ * {@code lowerValue} and {@code upperValue} included.
+ * <p>
+ * You can have half-open ranges by setting {@code lowerValue = null}
+ * or {@code upperValue = null}.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link BinaryPoint#newRangeQuery}.
+ */
+ public static Query newRangeQuery(String field,
+ BytesRef lowerValue, BytesRef upperValue,
+ boolean lowerInclusive, boolean upperInclusive) {
+ return new SortedSetDocValuesRangeQuery(field, lowerValue, upperValue, lowerInclusive, upperInclusive) {
+ @Override
+ SortedSetDocValues getValues(LeafReader reader, String field) throws IOException {
+ return DocValues.singleton(DocValues.getSorted(reader, field));
+ }
+ };
+ }
+
+ /**
+ * Create a query for matching an exact {@link BytesRef} value.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link BinaryPoint#newExactQuery}.
+ */
+ public static Query newExactQuery(String field, BytesRef value) {
+ return newRangeQuery(field, value, value, true, true);
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesField.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesField.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesField.java
index cbba218..6f9a271 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesField.java
@@ -17,7 +17,15 @@
package org.apache.lucene.document;
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
+import org.apache.lucene.search.Query;
/**
* <p>
@@ -63,4 +71,50 @@ public class SortedNumericDocValuesField extends Field {
super(name, TYPE);
fieldsData = Long.valueOf(value);
}
+
+ /**
+ * Create a range query that matches all documents whose value is between
+ * {@code lowerValue} and {@code upperValue} included.
+ * <p>
+ * You can have half-open ranges (which are in fact </≤ or >/≥ queries)
+ * by setting {@code lowerValue = Long.MIN_VALUE} or {@code upperValue = Long.MAX_VALUE}.
+ * <p>
+ * Ranges are inclusive. For exclusive ranges, pass {@code Math.addExact(lowerValue, 1)}
+ * or {@code Math.addExact(upperValue, -1)}.
+ * <p>This query also works with fields that have indexed
+ * {@link NumericDocValuesField}s.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link LongPoint#newRangeQuery}.
+ */
+ public static Query newRangeQuery(String field, long lowerValue, long upperValue) {
+ return new SortedNumericDocValuesRangeQuery(field, lowerValue, upperValue) {
+ @Override
+ SortedNumericDocValues getValues(LeafReader reader, String field) throws IOException {
+ FieldInfo info = reader.getFieldInfos().fieldInfo(field);
+ if (info == null) {
+ // Queries have some optimizations when one sub scorer returns null rather
+ // than a scorer that does not match any documents
+ return null;
+ }
+ return DocValues.getSortedNumeric(reader, field);
+ }
+ };
+ }
+
+ /**
+ * Create a query for matching an exact long value.
+ * <p>This query also works with fields that have indexed
+ * {@link NumericDocValuesField}s.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link LongPoint#newExactQuery}.
+ */
+ public static Query newExactQuery(String field, long value) {
+ return newRangeQuery(field, value, value);
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
new file mode 100644
index 0000000..ffe953c
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
@@ -0,0 +1,150 @@
+/*
+ * 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.lucene.document;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.search.ConstantScoreScorer;
+import org.apache.lucene.search.ConstantScoreWeight;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.FieldValueQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.TwoPhaseIterator;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.Bits;
+
+abstract class SortedNumericDocValuesRangeQuery extends Query {
+
+ private final String field;
+ private final long lowerValue;
+ private final long upperValue;
+
+ SortedNumericDocValuesRangeQuery(String field, long lowerValue, long upperValue) {
+ this.field = Objects.requireNonNull(field);
+ this.lowerValue = lowerValue;
+ this.upperValue = upperValue;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (sameClassAs(obj) == false) {
+ return false;
+ }
+ SortedNumericDocValuesRangeQuery that = (SortedNumericDocValuesRangeQuery) obj;
+ return Objects.equals(field, that.field)
+ && lowerValue == that.lowerValue
+ && upperValue == that.upperValue;
+ }
+
+ @Override
+ public int hashCode() {
+ int h = classHash();
+ h = 31 * h + field.hashCode();
+ h = 31 * h + Long.hashCode(lowerValue);
+ h = 31 * h + Long.hashCode(upperValue);
+ return h;
+ }
+
+ @Override
+ public String toString(String field) {
+ StringBuilder b = new StringBuilder();
+ if (this.field.equals(field) == false) {
+ b.append(this.field).append(":");
+ }
+ return b
+ .append("[")
+ .append(lowerValue)
+ .append(" TO ")
+ .append(upperValue)
+ .append("]")
+ .toString();
+ }
+
+ @Override
+ public Query rewrite(IndexReader reader) throws IOException {
+ if (lowerValue == Long.MIN_VALUE && upperValue == Long.MAX_VALUE) {
+ return new FieldValueQuery(field);
+ }
+ return super.rewrite(reader);
+ }
+
+ abstract SortedNumericDocValues getValues(LeafReader reader, String field) throws IOException;
+
+ @Override
+ public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+ return new ConstantScoreWeight(this) {
+ @Override
+ public Scorer scorer(LeafReaderContext context) throws IOException {
+ SortedNumericDocValues values = getValues(context.reader(), field);
+ if (values == null) {
+ return null;
+ }
+ final NumericDocValues singleton = DocValues.unwrapSingleton(values);
+ final TwoPhaseIterator iterator;
+ final DocIdSetIterator approximation = DocIdSetIterator.all(context.reader().maxDoc());
+ if (singleton != null) {
+ final Bits docsWithField = DocValues.unwrapSingletonBits(values);
+ iterator = new TwoPhaseIterator(approximation) {
+ @Override
+ public boolean matches() throws IOException {
+ final long value = singleton.get(approximation.docID());
+ return (value != 0 || docsWithField.get(approximation.docID()))
+ && value >= lowerValue && value <= upperValue;
+ }
+
+ @Override
+ public float matchCost() {
+ return 2; // 2 comparisons
+ }
+ };
+ } else {
+ iterator = new TwoPhaseIterator(approximation) {
+ @Override
+ public boolean matches() throws IOException {
+ values.setDocument(approximation.docID());
+ for (int i = 0, count = values.count(); i < count; ++i) {
+ final long value = values.valueAt(i);
+ if (value < lowerValue) {
+ continue;
+ }
+ // Values are sorted, so the first value that is >= lowerValue is our best candidate
+ return value <= upperValue;
+ }
+ return false; // all values were < lowerValue
+ }
+
+ @Override
+ public float matchCost() {
+ return 2; // 2 comparisons
+ }
+ };
+ }
+ return new ConstantScoreScorer(this, score(), iterator);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesField.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesField.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesField.java
index 7a273ac..26b1907 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesField.java
@@ -17,7 +17,14 @@
package org.apache.lucene.document;
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
+import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
/**
@@ -60,4 +67,40 @@ public class SortedSetDocValuesField extends Field {
super(name, TYPE);
fieldsData = bytes;
}
+
+ /**
+ * Create a range query that matches all documents whose value is between
+ * {@code lowerValue} and {@code upperValue}.
+ * <p>This query also works with fields that have indexed
+ * {@link SortedDocValuesField}s.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link BinaryPoint#newRangeQuery}.
+ */
+ public static Query newRangeQuery(String field,
+ BytesRef lowerValue, BytesRef upperValue,
+ boolean lowerInclusive, boolean upperInclusive) {
+ return new SortedSetDocValuesRangeQuery(field, lowerValue, upperValue, lowerInclusive, upperInclusive) {
+ @Override
+ SortedSetDocValues getValues(LeafReader reader, String field) throws IOException {
+ return DocValues.getSortedSet(reader, field);
+ }
+ };
+ }
+
+ /**
+ * Create a query for matching an exact {@link BytesRef} value.
+ * <p>This query also works with fields that have indexed
+ * {@link SortedDocValuesField}s.
+ * <p><b>NOTE</b>: Such queries cannot efficiently advance to the next match,
+ * which makes them slow if they are not ANDed with a selective query. As a
+ * consequence, they are best used wrapped in an {@link IndexOrDocValuesQuery},
+ * alongside a range query that executes on points, such as
+ * {@link BinaryPoint#newExactQuery}.
+ */
+ public static Query newExactQuery(String field, BytesRef value) {
+ return newRangeQuery(field, value, value, true, true);
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
new file mode 100644
index 0000000..854eb43
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
@@ -0,0 +1,190 @@
+/*
+ * 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.lucene.document;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.search.ConstantScoreScorer;
+import org.apache.lucene.search.ConstantScoreWeight;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.FieldValueQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.TwoPhaseIterator;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.BytesRef;
+
+abstract class SortedSetDocValuesRangeQuery extends Query {
+
+ private final String field;
+ private final BytesRef lowerValue;
+ private final BytesRef upperValue;
+ private final boolean lowerInclusive;
+ private final boolean upperInclusive;
+
+ SortedSetDocValuesRangeQuery(String field,
+ BytesRef lowerValue, BytesRef upperValue,
+ boolean lowerInclusive, boolean upperInclusive) {
+ this.field = Objects.requireNonNull(field);
+ this.lowerValue = lowerValue;
+ this.upperValue = upperValue;
+ this.lowerInclusive = lowerInclusive && lowerValue != null;
+ this.upperInclusive = upperInclusive && upperValue != null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (sameClassAs(obj) == false) {
+ return false;
+ }
+ SortedSetDocValuesRangeQuery that = (SortedSetDocValuesRangeQuery) obj;
+ return Objects.equals(field, that.field)
+ && Objects.equals(lowerValue, that.lowerValue)
+ && Objects.equals(upperValue, that.upperValue)
+ && lowerInclusive == that.lowerInclusive
+ && upperInclusive == that.upperInclusive;
+ }
+
+ @Override
+ public int hashCode() {
+ int h = classHash();
+ h = 31 * h + field.hashCode();
+ h = 31 * h + Objects.hashCode(lowerValue);
+ h = 31 * h + Objects.hashCode(upperValue);
+ h = 31 * h + Boolean.hashCode(lowerInclusive);
+ h = 31 * h + Boolean.hashCode(upperInclusive);
+ return h;
+ }
+
+ @Override
+ public String toString(String field) {
+ StringBuilder b = new StringBuilder();
+ if (this.field.equals(field) == false) {
+ b.append(this.field).append(":");
+ }
+ return b
+ .append(lowerInclusive ? "[" : "{")
+ .append(lowerValue == null ? "*" : lowerValue)
+ .append(" TO ")
+ .append(upperValue == null ? "*" : upperValue)
+ .append(upperInclusive ? "]" : "}")
+ .toString();
+ }
+
+ @Override
+ public Query rewrite(IndexReader reader) throws IOException {
+ if (lowerValue == null && upperValue == null) {
+ return new FieldValueQuery(field);
+ }
+ return super.rewrite(reader);
+ }
+
+ abstract SortedSetDocValues getValues(LeafReader reader, String field) throws IOException;
+
+ @Override
+ public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+ return new ConstantScoreWeight(this) {
+ @Override
+ public Scorer scorer(LeafReaderContext context) throws IOException {
+ SortedSetDocValues values = getValues(context.reader(), field);
+ if (values == null) {
+ return null;
+ }
+
+ final long minOrd;
+ if (lowerValue == null) {
+ minOrd = 0;
+ } else {
+ final long ord = values.lookupTerm(lowerValue);
+ if (ord < 0) {
+ minOrd = -1 - ord;
+ } else if (lowerInclusive) {
+ minOrd = ord;
+ } else {
+ minOrd = ord + 1;
+ }
+ }
+
+ final long maxOrd;
+ if (upperValue == null) {
+ maxOrd = values.getValueCount() - 1;
+ } else {
+ final long ord = values.lookupTerm(upperValue);
+ if (ord < 0) {
+ maxOrd = -2 - ord;
+ } else if (upperInclusive) {
+ maxOrd = ord;
+ } else {
+ maxOrd = ord - 1;
+ }
+ }
+
+ if (minOrd > maxOrd) {
+ return null;
+ }
+
+ final SortedDocValues singleton = DocValues.unwrapSingleton(values);
+ final DocIdSetIterator approximation = DocIdSetIterator.all(context.reader().maxDoc());
+ final TwoPhaseIterator iterator;
+ if (singleton != null) {
+ iterator = new TwoPhaseIterator(approximation) {
+ @Override
+ public boolean matches() throws IOException {
+ final long ord = singleton.getOrd(approximation.docID());
+ return ord >= minOrd && ord <= maxOrd;
+ }
+
+ @Override
+ public float matchCost() {
+ return 2; // 2 comparisons
+ }
+ };
+ } else {
+ iterator = new TwoPhaseIterator(approximation) {
+ @Override
+ public boolean matches() throws IOException {
+ values.setDocument(approximation.docID());
+ for (long ord = values.nextOrd(); ord != SortedSetDocValues.NO_MORE_ORDS; ord = values.nextOrd()) {
+ if (ord < minOrd) {
+ continue;
+ }
+ // Values are sorted, so the first ord that is >= minOrd is our best candidate
+ return ord <= maxOrd;
+ }
+ return false; // all ords were < minOrd
+ }
+
+ @Override
+ public float matchCost() {
+ return 2; // 2 comparisons
+ }
+ };
+ }
+ return new ConstantScoreScorer(this, score(), iterator);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
new file mode 100644
index 0000000..2b85b18
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
@@ -0,0 +1,177 @@
+/*
+ * 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.lucene.search;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.SortedNumericDocValuesField;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.Term;
+
+/**
+ * A query that uses either an index structure (points or terms) or doc values
+ * in order to run a query, depending which one is more efficient. This is
+ * typically useful for range queries, whose {@link Weight#scorer} is costly
+ * to create since it usually needs to sort large lists of doc ids. For
+ * instance, for a field that both indexed {@link LongPoint}s and
+ * {@link SortedNumericDocValuesField}s with the same values, an efficient
+ * range query could be created by doing:
+ * <pre class="prettyprint">
+ * String field;
+ * long minValue, maxValue;
+ * Query pointQuery = LongPoint.newRangeQuery(field, minValue, maxValue);
+ * Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field, minValue, maxValue);
+ * Query query = new IndexOrDocValuesQuery(pointQuery, dvQuery);
+ * </pre>
+ * The above query will be efficient as it will use points in the case that they
+ * perform better, ie. when we need a good lead iterator that will be almost
+ * entirely consumed; and doc values otherwise, ie. in the case that another
+ * part of the query is already leading iteration but we still need the ability
+ * to verify that some documents match.
+ * <p><b>NOTE</b>This query currently only works well with point range/exact
+ * queries and their equivalent doc values queries.
+ * @lucene.experimental
+ */
+public final class IndexOrDocValuesQuery extends Query {
+
+ private final Query indexQuery, dvQuery;
+
+ /**
+ * Create an {@link IndexOrDocValuesQuery}. Both provided queries must match
+ * the same documents and give the same scores.
+ * @param indexQuery a query that has a good iterator but whose scorer may be costly to create
+ * @param dvQuery a query whose scorer is cheap to create that can quickly check whether a given document matches
+ */
+ public IndexOrDocValuesQuery(Query indexQuery, Query dvQuery) {
+ this.indexQuery = indexQuery;
+ this.dvQuery = dvQuery;
+ }
+
+ /** Return the wrapped query that may be costly to initialize but has a good
+ * iterator. */
+ public Query getIndexQuery() {
+ return indexQuery;
+ }
+
+ /** Return the wrapped query that may be slow at identifying all matching
+ * documents, but which is cheap to initialize and can efficiently
+ * verify that some documents match. */
+ public Query getRandomAccessQuery() {
+ return dvQuery;
+ }
+
+ @Override
+ public String toString(String field) {
+ return indexQuery.toString(field);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (sameClassAs(obj) == false) {
+ return false;
+ }
+ IndexOrDocValuesQuery that = (IndexOrDocValuesQuery) obj;
+ return indexQuery.equals(that.indexQuery) && dvQuery.equals(that.dvQuery);
+ }
+
+ @Override
+ public int hashCode() {
+ int h = classHash();
+ h = 31 * h + indexQuery.hashCode();
+ h = 31 * h + dvQuery.hashCode();
+ return h;
+ }
+
+ @Override
+ public Query rewrite(IndexReader reader) throws IOException {
+ Query indexRewrite = indexQuery.rewrite(reader);
+ Query dvRewrite = dvQuery.rewrite(reader);
+ if (indexQuery != indexRewrite || dvQuery != dvRewrite) {
+ return new IndexOrDocValuesQuery(indexRewrite, dvRewrite);
+ }
+ return this;
+ }
+
+ @Override
+ public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+ final Weight indexWeight = indexQuery.createWeight(searcher, needsScores);
+ final Weight dvWeight = dvQuery.createWeight(searcher, needsScores);
+ return new Weight(this) {
+ @Override
+ public void extractTerms(Set<Term> terms) {
+ indexWeight.extractTerms(terms);
+ }
+
+ @Override
+ public void normalize(float norm, float boost) {
+ indexWeight.normalize(norm, boost);
+ dvWeight.normalize(norm, boost);
+ }
+
+ @Override
+ public float getValueForNormalization() throws IOException {
+ return indexWeight.getValueForNormalization();
+ }
+
+ @Override
+ public Explanation explain(LeafReaderContext context, int doc) throws IOException {
+ // We need to check a single doc, so the dv query should perform better
+ return dvWeight.explain(context, doc);
+ }
+
+ @Override
+ public BulkScorer bulkScorer(LeafReaderContext context) throws IOException {
+ // Bulk scorers need to consume the entire set of docs, so using an
+ // index structure should perform better
+ return indexWeight.bulkScorer(context);
+ }
+
+ @Override
+ public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
+ final ScorerSupplier indexScorerSupplier = indexWeight.scorerSupplier(context);
+ final ScorerSupplier dvScorerSupplier = dvWeight.scorerSupplier(context);
+ if (indexScorerSupplier == null || dvScorerSupplier == null) {
+ return null;
+ }
+ return new ScorerSupplier() {
+ @Override
+ public Scorer get(boolean randomAccess) throws IOException {
+ return (randomAccess ? dvScorerSupplier : indexScorerSupplier).get(randomAccess);
+ }
+
+ @Override
+ public long cost() {
+ return Math.min(indexScorerSupplier.cost(), dvScorerSupplier.cost());
+ }
+ };
+ }
+
+ @Override
+ public Scorer scorer(LeafReaderContext context) throws IOException {
+ ScorerSupplier scorerSupplier = scorerSupplier(context);
+ if (scorerSupplier == null) {
+ return null;
+ }
+ return scorerSupplier.get(false);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java
new file mode 100644
index 0000000..501538f
--- /dev/null
+++ b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java
@@ -0,0 +1,238 @@
+/*
+ * 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.lucene.search;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.document.SortedDocValuesField;
+import org.apache.lucene.document.SortedNumericDocValuesField;
+import org.apache.lucene.document.SortedSetDocValuesField;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+
+public class TestDocValuesQueries extends LuceneTestCase {
+
+ public void testDuelPointRangeSortedNumericRangeQuery() throws IOException {
+ doTestDuelPointRangeNumericRangeQuery(true, 1);
+ }
+
+ public void testDuelPointRangeMultivaluedSortedNumericRangeQuery() throws IOException {
+ doTestDuelPointRangeNumericRangeQuery(true, 3);
+ }
+
+ public void testDuelPointRangeNumericRangeQuery() throws IOException {
+ doTestDuelPointRangeNumericRangeQuery(false, 1);
+ }
+
+ private void doTestDuelPointRangeNumericRangeQuery(boolean sortedNumeric, int maxValuesPerDoc) throws IOException {
+ final int iters = atLeast(10);
+ for (int iter = 0; iter < iters; ++iter) {
+ Directory dir = newDirectory();
+ RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
+ final int numDocs = atLeast(100);
+ for (int i = 0; i < numDocs; ++i) {
+ Document doc = new Document();
+ final int numValues = TestUtil.nextInt(random(), 0, maxValuesPerDoc);
+ for (int j = 0; j < numValues; ++j) {
+ final long value = TestUtil.nextLong(random(), -100, 10000);
+ if (sortedNumeric) {
+ doc.add(new SortedNumericDocValuesField("dv", value));
+ } else {
+ doc.add(new NumericDocValuesField("dv", value));
+ }
+ doc.add(new LongPoint("idx", value));
+ }
+ iw.addDocument(doc);
+ }
+ if (random().nextBoolean()) {
+ iw.deleteDocuments(LongPoint.newRangeQuery("idx", 0L, 10L));
+ }
+ final IndexReader reader = iw.getReader();
+ final IndexSearcher searcher = newSearcher(reader, false);
+ iw.close();
+
+ for (int i = 0; i < 100; ++i) {
+ final long min = random().nextBoolean() ? Long.MIN_VALUE : TestUtil.nextLong(random(), -100, 10000);
+ final long max = random().nextBoolean() ? Long.MAX_VALUE : TestUtil.nextLong(random(), -100, 10000);
+ final Query q1 = LongPoint.newRangeQuery("idx", min, max);
+ final Query q2;
+ if (sortedNumeric) {
+ q2 = SortedNumericDocValuesField.newRangeQuery("dv", min, max);
+ } else {
+ q2 = NumericDocValuesField.newRangeQuery("dv", min, max);
+ }
+ assertSameMatches(searcher, q1, q2, false);
+ }
+
+ reader.close();
+ dir.close();
+ }
+ }
+
+ private void doTestDuelPointRangeSortedRangeQuery(boolean sortedSet, int maxValuesPerDoc) throws IOException {
+ final int iters = atLeast(10);
+ for (int iter = 0; iter < iters; ++iter) {
+ Directory dir = newDirectory();
+ RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
+ final int numDocs = atLeast(100);
+ for (int i = 0; i < numDocs; ++i) {
+ Document doc = new Document();
+ final int numValues = TestUtil.nextInt(random(), 0, maxValuesPerDoc);
+ for (int j = 0; j < numValues; ++j) {
+ final long value = TestUtil.nextLong(random(), -100, 10000);
+ byte[] encoded = new byte[Long.BYTES];
+ LongPoint.encodeDimension(value, encoded, 0);
+ if (sortedSet) {
+ doc.add(new SortedSetDocValuesField("dv", new BytesRef(encoded)));
+ } else {
+ doc.add(new SortedDocValuesField("dv", new BytesRef(encoded)));
+ }
+ doc.add(new LongPoint("idx", value));
+ }
+ iw.addDocument(doc);
+ }
+ if (random().nextBoolean()) {
+ iw.deleteDocuments(LongPoint.newRangeQuery("idx", 0L, 10L));
+ }
+ final IndexReader reader = iw.getReader();
+ final IndexSearcher searcher = newSearcher(reader, false);
+ iw.close();
+
+ for (int i = 0; i < 100; ++i) {
+ long min = random().nextBoolean() ? Long.MIN_VALUE : TestUtil.nextLong(random(), -100, 10000);
+ long max = random().nextBoolean() ? Long.MAX_VALUE : TestUtil.nextLong(random(), -100, 10000);
+ byte[] encodedMin = new byte[Long.BYTES];
+ byte[] encodedMax = new byte[Long.BYTES];
+ LongPoint.encodeDimension(min, encodedMin, 0);
+ LongPoint.encodeDimension(max, encodedMax, 0);
+ boolean includeMin = true;
+ boolean includeMax = true;
+ if (random().nextBoolean()) {
+ includeMin = false;
+ min++;
+ }
+ if (random().nextBoolean()) {
+ includeMax = false;
+ max--;
+ }
+ final Query q1 = LongPoint.newRangeQuery("idx", min, max);
+ final Query q2;
+ if (sortedSet) {
+ q2 = SortedSetDocValuesField.newRangeQuery("dv",
+ min == Long.MIN_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMin),
+ max == Long.MAX_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMax),
+ includeMin, includeMax);
+ } else {
+ q2 = SortedDocValuesField.newRangeQuery("dv",
+ min == Long.MIN_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMin),
+ max == Long.MAX_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMax),
+ includeMin, includeMax);
+ }
+ assertSameMatches(searcher, q1, q2, false);
+ }
+
+ reader.close();
+ dir.close();
+ }
+ }
+
+ public void testDuelPointRangeSortedSetRangeQuery() throws IOException {
+ doTestDuelPointRangeSortedRangeQuery(true, 1);
+ }
+
+ public void testDuelPointRangeMultivaluedSortedSetRangeQuery() throws IOException {
+ doTestDuelPointRangeSortedRangeQuery(true, 3);
+ }
+
+ public void testDuelPointRangeSortedRangeQuery() throws IOException {
+ doTestDuelPointRangeSortedRangeQuery(false, 1);
+ }
+
+ private void assertSameMatches(IndexSearcher searcher, Query q1, Query q2, boolean scores) throws IOException {
+ final int maxDoc = searcher.getIndexReader().maxDoc();
+ final TopDocs td1 = searcher.search(q1, maxDoc, scores ? Sort.RELEVANCE : Sort.INDEXORDER);
+ final TopDocs td2 = searcher.search(q2, maxDoc, scores ? Sort.RELEVANCE : Sort.INDEXORDER);
+ assertEquals(td1.totalHits, td2.totalHits);
+ for (int i = 0; i < td1.scoreDocs.length; ++i) {
+ assertEquals(td1.scoreDocs[i].doc, td2.scoreDocs[i].doc);
+ if (scores) {
+ assertEquals(td1.scoreDocs[i].score, td2.scoreDocs[i].score, 10e-7);
+ }
+ }
+ }
+
+ public void testEquals() {
+ Query q1 = SortedNumericDocValuesField.newRangeQuery("foo", 3, 5);
+ QueryUtils.checkEqual(q1, SortedNumericDocValuesField.newRangeQuery("foo", 3, 5));
+ QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("foo", 3, 6));
+ QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("foo", 4, 5));
+ QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("bar", 3, 5));
+
+ Query q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true);
+ QueryUtils.checkEqual(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true));
+ QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("baz"), new BytesRef("baz"), true, true));
+ QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("bar"), true, true));
+ QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("quux", new BytesRef("bar"), new BytesRef("baz"), true, true));
+ }
+
+ public void testToString() {
+ Query q1 = SortedNumericDocValuesField.newRangeQuery("foo", 3, 5);
+ assertEquals("foo:[3 TO 5]", q1.toString());
+ assertEquals("[3 TO 5]", q1.toString("foo"));
+ assertEquals("foo:[3 TO 5]", q1.toString("bar"));
+
+ Query q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true);
+ assertEquals("foo:[[62 61 72] TO [62 61 7a]]", q2.toString());
+ q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), false, true);
+ assertEquals("foo:{[62 61 72] TO [62 61 7a]]", q2.toString());
+ q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), false, false);
+ assertEquals("foo:{[62 61 72] TO [62 61 7a]}", q2.toString());
+ q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), null, true, true);
+ assertEquals("foo:[[62 61 72] TO *}", q2.toString());
+ q2 = SortedSetDocValuesField.newRangeQuery("foo", null, new BytesRef("baz"), true, true);
+ assertEquals("foo:{* TO [62 61 7a]]", q2.toString());
+ assertEquals("{* TO [62 61 7a]]", q2.toString("foo"));
+ assertEquals("foo:{* TO [62 61 7a]]", q2.toString("bar"));
+ }
+
+ public void testMissingField() throws IOException {
+ Directory dir = newDirectory();
+ RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
+ iw.addDocument(new Document());
+ IndexReader reader = iw.getReader();
+ iw.close();
+ IndexSearcher searcher = newSearcher(reader);
+ for (Query query : Arrays.asList(
+ NumericDocValuesField.newRangeQuery("foo", 2, 4),
+ SortedNumericDocValuesField.newRangeQuery("foo", 2, 4),
+ SortedDocValuesField.newRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()),
+ SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()))) {
+ Weight w = searcher.createNormalizedWeight(query, random().nextBoolean());
+ assertNull(w.scorer(searcher.getIndexReader().leaves().get(0)));
+ }
+ reader.close();
+ dir.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
new file mode 100644
index 0000000..8b81822
--- /dev/null
+++ b/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
@@ -0,0 +1,89 @@
+/*
+ * 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.lucene.search;
+
+import java.io.IOException;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+
+public class TestIndexOrDocValuesQuery extends LuceneTestCase {
+
+ public void testUseIndexForSelectiveQueries() throws IOException {
+ Directory dir = newDirectory();
+ IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()
+ // relies on costs and PointValues.estimateCost so we need the default codec
+ .setCodec(TestUtil.getDefaultCodec()));
+ for (int i = 0; i < 2000; ++i) {
+ Document doc = new Document();
+ if (i == 42) {
+ doc.add(new StringField("f1", "bar", Store.NO));
+ doc.add(new LongPoint("f2", 42L));
+ doc.add(new NumericDocValuesField("f2", 42L));
+ } else if (i == 100) {
+ doc.add(new StringField("f1", "foo", Store.NO));
+ doc.add(new LongPoint("f2", 2L));
+ doc.add(new NumericDocValuesField("f2", 2L));
+ } else {
+ doc.add(new StringField("f1", "bar", Store.NO));
+ doc.add(new LongPoint("f2", 2L));
+ doc.add(new NumericDocValuesField("f2", 2L));
+ }
+ w.addDocument(doc);
+ }
+ w.forceMerge(1);
+ IndexReader reader = DirectoryReader.open(w);
+ IndexSearcher searcher = newSearcher(reader);
+ searcher.setQueryCache(null);
+
+ // The term query is more selective, so the IndexOrDocValuesQuery should use doc values
+ final Query q1 = new BooleanQuery.Builder()
+ .add(new TermQuery(new Term("f1", "foo")), Occur.MUST)
+ .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 2), NumericDocValuesField.newRangeQuery("f2", 2L, 2L)), Occur.MUST)
+ .build();
+
+ final Weight w1 = searcher.createNormalizedWeight(q1, random().nextBoolean());
+ final Scorer s1 = w1.scorer(searcher.getIndexReader().leaves().get(0));
+ assertNotNull(s1.twoPhaseIterator()); // means we use doc values
+
+ // The term query is less selective, so the IndexOrDocValuesQuery should use points
+ final Query q2 = new BooleanQuery.Builder()
+ .add(new TermQuery(new Term("f1", "bar")), Occur.MUST)
+ .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 42), NumericDocValuesField.newRangeQuery("f2", 42L, 42L)), Occur.MUST)
+ .build();
+
+ final Weight w2 = searcher.createNormalizedWeight(q2, random().nextBoolean());
+ final Scorer s2 = w2.scorer(searcher.getIndexReader().leaves().get(0));
+ assertNull(s2.twoPhaseIterator()); // means we use points
+
+ reader.close();
+ w.close();
+ dir.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesRangeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesRangeQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesRangeQuery.java
index b71ebb2..02fbc51 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesRangeQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesRangeQuery.java
@@ -19,6 +19,8 @@ package org.apache.lucene.search;
import java.io.IOException;
import java.util.Objects;
+import org.apache.lucene.document.SortedNumericDocValuesField;
+import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexReader;
@@ -42,20 +44,24 @@ import org.apache.lucene.util.BytesRef;
* which allows to run the query on doc values when that would be more
* efficient, and using an index otherwise.
*
- * @lucene.experimental
+ * @deprecated Use factory method on doc value field classes
*/
+@Deprecated
public final class DocValuesRangeQuery extends Query {
/** Create a new numeric range query on a numeric doc-values field. The field
* must has been indexed with either {@link DocValuesType#NUMERIC} or
- * {@link DocValuesType#SORTED_NUMERIC} doc values. */
+ * {@link DocValuesType#SORTED_NUMERIC} doc values.
+ * @deprecated use {@link SortedNumericDocValuesField#newRangeQuery} */
+ @Deprecated
public static Query newLongRange(String field, Long lowerVal, Long upperVal, boolean includeLower, boolean includeUpper) {
return new DocValuesRangeQuery(field, lowerVal, upperVal, includeLower, includeUpper);
}
/** Create a new numeric range query on a numeric doc-values field. The field
* must has been indexed with {@link DocValuesType#SORTED} or
- * {@link DocValuesType#SORTED_SET} doc values. */
+ * {@link DocValuesType#SORTED_SET} doc values.
+ * @deprecated use {@link SortedSetDocValuesField#newRangeQuery} */
public static Query newBytesRefRange(String field, BytesRef lowerVal, BytesRef upperVal, boolean includeLower, boolean includeUpper) {
return new DocValuesRangeQuery(field, deepCopyOf(lowerVal), deepCopyOf(upperVal), includeLower, includeUpper);
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/sandbox/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
----------------------------------------------------------------------
diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
deleted file mode 100644
index 6ac980a..0000000
--- a/lucene/sandbox/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.lucene.search;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.LeafReaderContext;
-
-/**
- * A query that uses either an index (points or terms) or doc values in order
- * to run a range query, depending which one is more efficient.
- */
-public final class IndexOrDocValuesQuery extends Query {
-
- private final Query indexQuery, dvQuery;
-
- /**
- * Constructor that takes both a query that executes on an index structure
- * like the inverted index or the points tree, and another query that
- * executes on doc values. Both queries must match the same documents and
- * attribute constant scores.
- */
- public IndexOrDocValuesQuery(Query indexQuery, Query dvQuery) {
- this.indexQuery = indexQuery;
- this.dvQuery = dvQuery;
- }
-
- @Override
- public String toString(String field) {
- return indexQuery.toString(field);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (sameClassAs(obj) == false) {
- return false;
- }
- IndexOrDocValuesQuery that = (IndexOrDocValuesQuery) obj;
- return indexQuery.equals(that.indexQuery) && dvQuery.equals(that.dvQuery);
- }
-
- @Override
- public int hashCode() {
- int h = classHash();
- h = 31 * h + indexQuery.hashCode();
- h = 31 * h + dvQuery.hashCode();
- return h;
- }
-
- @Override
- public Query rewrite(IndexReader reader) throws IOException {
- Query indexRewrite = indexQuery.rewrite(reader);
- Query dvRewrite = dvQuery.rewrite(reader);
- if (indexQuery != indexRewrite || dvQuery != dvRewrite) {
- return new IndexOrDocValuesQuery(indexRewrite, dvRewrite);
- }
- return this;
- }
-
- @Override
- public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
- final Weight indexWeight = indexQuery.createWeight(searcher, needsScores);
- final Weight dvWeight = dvQuery.createWeight(searcher, needsScores);
- return new ConstantScoreWeight(this) {
- @Override
- public BulkScorer bulkScorer(LeafReaderContext context) throws IOException {
- return indexWeight.bulkScorer(context);
- }
-
- @Override
- public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
- final ScorerSupplier indexScorerSupplier = indexWeight.scorerSupplier(context);
- final ScorerSupplier dvScorerSupplier = dvWeight.scorerSupplier(context);
- if (indexScorerSupplier == null || dvScorerSupplier == null) {
- return null;
- }
- return new ScorerSupplier() {
- @Override
- public Scorer get(boolean randomAccess) throws IOException {
- return (randomAccess ? dvScorerSupplier : indexScorerSupplier).get(randomAccess);
- }
-
- @Override
- public long cost() {
- return Math.min(indexScorerSupplier.cost(), dvScorerSupplier.cost());
- }
- };
- }
-
- @Override
- public Scorer scorer(LeafReaderContext context) throws IOException {
- ScorerSupplier scorerSupplier = scorerSupplier(context);
- if (scorerSupplier == null) {
- return null;
- }
- return scorerSupplier.get(false);
- }
- };
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/lucene/sandbox/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
----------------------------------------------------------------------
diff --git a/lucene/sandbox/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java b/lucene/sandbox/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
deleted file mode 100644
index de289e7..0000000
--- a/lucene/sandbox/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.lucene.search;
-
-import java.io.IOException;
-
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field.Store;
-import org.apache.lucene.document.LongPoint;
-import org.apache.lucene.document.NumericDocValuesField;
-import org.apache.lucene.document.StringField;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.BooleanClause.Occur;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.TestUtil;
-
-public class TestIndexOrDocValuesQuery extends LuceneTestCase {
-
- public void testUseIndexForSelectiveQueries() throws IOException {
- Directory dir = newDirectory();
- IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()
- // relies on costs and PointValues.estimateCost so we need the default codec
- .setCodec(TestUtil.getDefaultCodec()));
- for (int i = 0; i < 2000; ++i) {
- Document doc = new Document();
- if (i == 42) {
- doc.add(new StringField("f1", "bar", Store.NO));
- doc.add(new LongPoint("f2", 42L));
- doc.add(new NumericDocValuesField("f2", 42L));
- } else if (i == 100) {
- doc.add(new StringField("f1", "foo", Store.NO));
- doc.add(new LongPoint("f2", 2L));
- doc.add(new NumericDocValuesField("f2", 2L));
- } else {
- doc.add(new StringField("f1", "bar", Store.NO));
- doc.add(new LongPoint("f2", 2L));
- doc.add(new NumericDocValuesField("f2", 2L));
- }
- w.addDocument(doc);
- }
- w.forceMerge(1);
- IndexReader reader = DirectoryReader.open(w);
- IndexSearcher searcher = newSearcher(reader);
- searcher.setQueryCache(null);
-
- // The term query is more selective, so the IndexOrDocValuesQuery should use doc values
- final Query q1 = new BooleanQuery.Builder()
- .add(new TermQuery(new Term("f1", "foo")), Occur.MUST)
- .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 2), new DocValuesNumbersQuery("f2", 2L)), Occur.MUST)
- .build();
-
- final Weight w1 = searcher.createNormalizedWeight(q1, random().nextBoolean());
- final Scorer s1 = w1.scorer(searcher.getIndexReader().leaves().get(0));
- assertNotNull(s1.twoPhaseIterator()); // means we use doc values
-
- // The term query is less selective, so the IndexOrDocValuesQuery should use points
- final Query q2 = new BooleanQuery.Builder()
- .add(new TermQuery(new Term("f1", "bar")), Occur.MUST)
- .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 42), new DocValuesNumbersQuery("f2", 42L)), Occur.MUST)
- .build();
-
- final Weight w2 = searcher.createNormalizedWeight(q2, random().nextBoolean());
- final Scorer s2 = w2.scorer(searcher.getIndexReader().leaves().get(0));
- assertNull(s2.twoPhaseIterator()); // means we use points
-
- reader.close();
- w.close();
- dir.close();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/solr/contrib/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java b/solr/contrib/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
index 2071163..5152768 100644
--- a/solr/contrib/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
+++ b/solr/contrib/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
@@ -32,7 +32,6 @@ import org.apache.lucene.collation.ICUCollationKeyAnalyzer;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.search.DocValuesRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermRangeQuery;
@@ -272,13 +271,8 @@ public class ICUCollationField extends FieldType {
BytesRef low = part1 == null ? null : getCollationKey(f, part1);
BytesRef high = part2 == null ? null : getCollationKey(f, part2);
if (!field.indexed() && field.hasDocValues()) {
- if (field.multiValued()) {
- return DocValuesRangeQuery.newBytesRefRange(
- field.getName(), low, high, minInclusive, maxInclusive);
- } else {
- return DocValuesRangeQuery.newBytesRefRange(
- field.getName(), low, high, minInclusive, maxInclusive);
- }
+ return SortedSetDocValuesField.newRangeQuery(
+ field.getName(), low, high, minInclusive, maxInclusive);
} else {
return new TermRangeQuery(field.getName(), low, high, minInclusive, maxInclusive);
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/solr/core/src/java/org/apache/solr/schema/CollationField.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/CollationField.java b/solr/core/src/java/org/apache/solr/schema/CollationField.java
index 998db2a..805e204 100644
--- a/solr/core/src/java/org/apache/solr/schema/CollationField.java
+++ b/solr/core/src/java/org/apache/solr/schema/CollationField.java
@@ -36,7 +36,6 @@ import org.apache.lucene.collation.CollationKeyAnalyzer;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.search.DocValuesRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermRangeQuery;
@@ -242,7 +241,7 @@ public class CollationField extends FieldType {
BytesRef low = part1 == null ? null : getCollationKey(f, part1);
BytesRef high = part2 == null ? null : getCollationKey(f, part2);
if (!field.indexed() && field.hasDocValues()) {
- return DocValuesRangeQuery.newBytesRefRange(
+ return SortedSetDocValuesField.newRangeQuery(
field.getName(), low, high, minInclusive, maxInclusive);
} else {
return new TermRangeQuery(field.getName(), low, high, minInclusive, maxInclusive);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/solr/core/src/java/org/apache/solr/schema/EnumField.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/EnumField.java b/solr/core/src/java/org/apache/solr/schema/EnumField.java
index 27f3a0a..828274c 100644
--- a/solr/core/src/java/org/apache/solr/schema/EnumField.java
+++ b/solr/core/src/java/org/apache/solr/schema/EnumField.java
@@ -41,7 +41,6 @@ import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.EnumFieldSource;
import org.apache.lucene.search.ConstantScoreQuery;
-import org.apache.lucene.search.DocValuesRangeQuery;
import org.apache.lucene.search.LegacyNumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
@@ -253,10 +252,21 @@ public class EnumField extends PrimitiveFieldType {
Query query = null;
final boolean matchOnly = field.hasDocValues() && !field.indexed();
if (matchOnly) {
- query = new ConstantScoreQuery(DocValuesRangeQuery.newLongRange(field.getName(),
- min == null ? null : minValue.longValue(),
- max == null ? null : maxValue.longValue(),
- minInclusive, maxInclusive));
+ long lowerValue = Long.MIN_VALUE;
+ long upperValue = Long.MAX_VALUE;
+ if (minValue != null) {
+ lowerValue = minValue.longValue();
+ if (minInclusive == false) {
+ ++lowerValue;
+ }
+ }
+ if (maxValue != null) {
+ upperValue = maxValue.longValue();
+ if (maxInclusive == false) {
+ --upperValue;
+ }
+ }
+ query = new ConstantScoreQuery(NumericDocValuesField.newRangeQuery(field.getName(), lowerValue, upperValue));
} else {
query = LegacyNumericRangeQuery.newIntRange(field.getName(), DEFAULT_PRECISION_STEP,
min == null ? null : minValue,
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/solr/core/src/java/org/apache/solr/schema/FieldType.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/FieldType.java b/solr/core/src/java/org/apache/solr/schema/FieldType.java
index 4ba4106..accca3b 100644
--- a/solr/core/src/java/org/apache/solr/schema/FieldType.java
+++ b/solr/core/src/java/org/apache/solr/schema/FieldType.java
@@ -37,12 +37,12 @@ import org.apache.lucene.analysis.util.TokenFilterFactory;
import org.apache.lucene.analysis.util.TokenizerFactory;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexOptions;
+import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.DocValuesRangeQuery;
import org.apache.lucene.search.DocValuesRewriteMethod;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.PrefixQuery;
@@ -728,17 +728,17 @@ public abstract class FieldType extends FieldProperties {
*/
public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
// TODO: change these all to use readableToIndexed/bytes instead (e.g. for unicode collation)
+ final BytesRef miValue = part1 == null ? null : new BytesRef(toInternal(part1));
+ final BytesRef maxValue = part2 == null ? null : new BytesRef(toInternal(part2));
if (field.hasDocValues() && !field.indexed()) {
- return DocValuesRangeQuery.newBytesRefRange(
- field.getName(),
- part1 == null ? null : new BytesRef(toInternal(part1)),
- part2 == null ? null : new BytesRef(toInternal(part2)),
- minInclusive, maxInclusive);
+ return SortedSetDocValuesField.newRangeQuery(
+ field.getName(),
+ miValue, maxValue,
+ minInclusive, maxInclusive);
} else {
SolrRangeQuery rangeQuery = new SolrRangeQuery(
field.getName(),
- part1 == null ? null : new BytesRef(toInternal(part1)),
- part2 == null ? null : new BytesRef(toInternal(part2)),
+ miValue, maxValue,
minInclusive, maxInclusive);
return rangeQuery;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/20b7dfae/solr/core/src/java/org/apache/solr/schema/TrieField.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/TrieField.java b/solr/core/src/java/org/apache/solr/schema/TrieField.java
index b7bac1c..21a35bb 100644
--- a/solr/core/src/java/org/apache/solr/schema/TrieField.java
+++ b/solr/core/src/java/org/apache/solr/schema/TrieField.java
@@ -42,8 +42,8 @@ import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
import org.apache.lucene.queries.function.valuesource.IntFieldSource;
import org.apache.lucene.queries.function.valuesource.LongFieldSource;
-import org.apache.lucene.search.DocValuesRangeQuery;
import org.apache.lucene.search.LegacyNumericRangeQuery;
+import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedSetSelector;
@@ -377,9 +377,9 @@ public class TrieField extends PrimitiveFieldType {
switch (type) {
case INTEGER:
if (matchOnly) {
- query = DocValuesRangeQuery.newLongRange(field.getName(),
- min == null ? null : (long) Integer.parseInt(min),
- max == null ? null : (long) Integer.parseInt(max),
+ query = numericDocValuesRangeQuery(field.getName(),
+ min == null ? null : Integer.parseInt(min),
+ max == null ? null : Integer.parseInt(max),
minInclusive, maxInclusive);
} else {
query = LegacyNumericRangeQuery.newIntRange(field.getName(), ps,
@@ -400,7 +400,7 @@ public class TrieField extends PrimitiveFieldType {
break;
case LONG:
if (matchOnly) {
- query = DocValuesRangeQuery.newLongRange(field.getName(),
+ query = numericDocValuesRangeQuery(field.getName(),
min == null ? null : Long.parseLong(min),
max == null ? null : Long.parseLong(max),
minInclusive, maxInclusive);
@@ -423,7 +423,7 @@ public class TrieField extends PrimitiveFieldType {
break;
case DATE:
if (matchOnly) {
- query = DocValuesRangeQuery.newLongRange(field.getName(),
+ query = numericDocValuesRangeQuery(field.getName(),
min == null ? null : DateMathParser.parseMath(null, min).getTime(),
max == null ? null : DateMathParser.parseMath(null, max).getTime(),
minInclusive, maxInclusive);
@@ -441,6 +441,35 @@ public class TrieField extends PrimitiveFieldType {
return query;
}
+ private static Query numericDocValuesRangeQuery(
+ String field,
+ Number lowerValue, Number upperValue,
+ boolean lowerInclusive, boolean upperInclusive) {
+
+ long actualLowerValue = Long.MIN_VALUE;
+ if (lowerValue != null) {
+ actualLowerValue = lowerValue.longValue();
+ if (lowerInclusive == false) {
+ if (actualLowerValue == Long.MAX_VALUE) {
+ return new MatchNoDocsQuery();
+ }
+ ++actualLowerValue;
+ }
+ }
+
+ long actualUpperValue = Long.MAX_VALUE;
+ if (upperValue != null) {
+ actualUpperValue = upperValue.longValue();
+ if (upperInclusive == false) {
+ if (actualUpperValue == Long.MIN_VALUE) {
+ return new MatchNoDocsQuery();
+ }
+ --actualUpperValue;
+ }
+ }
+ return NumericDocValuesField.newRangeQuery(field, actualLowerValue, actualUpperValue);
+ }
+
private static long FLOAT_NEGATIVE_INFINITY_BITS = (long)Float.floatToIntBits(Float.NEGATIVE_INFINITY);
private static long DOUBLE_NEGATIVE_INFINITY_BITS = Double.doubleToLongBits(Double.NEGATIVE_INFINITY);
private static long FLOAT_POSITIVE_INFINITY_BITS = (long)Float.floatToIntBits(Float.POSITIVE_INFINITY);
@@ -477,10 +506,10 @@ public class TrieField extends PrimitiveFieldType {
} else { // If both max and min are negative (or -0d), then issue range query with max and min reversed
if ((minVal == null || minVal.doubleValue() < 0d || minBits == minusZeroBits) &&
(maxVal != null && (maxVal.doubleValue() < 0d || maxBits == minusZeroBits))) {
- query = DocValuesRangeQuery.newLongRange
+ query = numericDocValuesRangeQuery
(fieldName, maxBits, (min == null ? negativeInfinityBits : minBits), maxInclusive, minInclusive);
} else { // If both max and min are positive, then issue range query
- query = DocValuesRangeQuery.newLongRange
+ query = numericDocValuesRangeQuery
(fieldName, minBits, (max == null ? positiveInfinityBits : maxBits), minInclusive, maxInclusive);
}
}