diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java index 7834ce4a504..301cf8d4b95 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java @@ -16,11 +16,15 @@ */ package org.apache.lucene.document; +import java.io.IOException; +import java.util.Objects; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValuesSkipper; import org.apache.lucene.index.LeafReaderContext; 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.FieldExistsQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -32,9 +36,6 @@ import org.apache.lucene.search.SortedSetDocValuesRangeScorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BytesRef; -import java.io.IOException; -import java.util.Objects; - final class SortedSetDocValuesRangeQuery extends Query { private final String field; @@ -148,7 +149,15 @@ final class SortedSetDocValuesRangeQuery extends Query { } } - return new SortedSetDocValuesRangeScorer(field, values, minOrd, maxOrd, scoreMode, score(), skipper, context); + // no terms matched in this segment + if (minOrd > maxOrd + || (skipper != null + && (minOrd > skipper.maxValue() || maxOrd < skipper.minValue()))) { + return new ConstantScoreScorer(score(), scoreMode, DocIdSetIterator.empty()); + } + + return new SortedSetDocValuesRangeScorer( + field, values, minOrd, maxOrd, scoreMode, score(), skipper, context.reader()); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java index c0b5f76425e..d4d98f8b908 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java @@ -178,24 +178,35 @@ public final class DocValuesRewriteMethod extends MultiTermQuery.RewriteMethod { assert minOrd >= 0; long maxOrd = -1; long prev = minOrd - 1; - boolean hasGaps = false; + boolean contiguous = true; do { long ord = termsEnum.ord(); assert ord >= 0 && ord > maxOrd; if (ord - prev > 1) { - hasGaps = true; + contiguous = false; } prev = ord; maxOrd = ord; termSet.set(ord); } while (termsEnum.next() != null); + // no terms matched in this segment if (skipper != null && (minOrd > skipper.maxValue() || maxOrd < skipper.minValue())) { return new ConstantScoreScorer(score(), scoreMode, DocIdSetIterator.empty()); } - if (hasGaps == false) { - return new SortedSetDocValuesRangeScorer(query.field, values, minOrd, maxOrd, scoreMode, score(), skipper, context); + // if the term set happens to create a contiguous range we can optimize with a range + // scorer + if (contiguous) { + return new SortedSetDocValuesRangeScorer( + query.field, + values, + minOrd, + maxOrd, + scoreMode, + score(), + skipper, + context.reader()); } final SortedDocValues singleton = DocValues.unwrapSingleton(values); diff --git a/lucene/core/src/java/org/apache/lucene/search/SortedSetDocValuesRangeScorer.java b/lucene/core/src/java/org/apache/lucene/search/SortedSetDocValuesRangeScorer.java index 148523d7e70..5267acf5299 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SortedSetDocValuesRangeScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/SortedSetDocValuesRangeScorer.java @@ -16,17 +16,24 @@ */ package org.apache.lucene.search; -import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.DocValuesSkipper; -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 java.io.IOException; import java.util.Collection; import java.util.function.LongPredicate; +import org.apache.lucene.index.DocValues; +import org.apache.lucene.index.DocValuesSkipper; +import org.apache.lucene.index.LeafReader; +import org.apache.lucene.index.SortedDocValues; +import org.apache.lucene.index.SortedSetDocValues; +/** + * Implements a "slow" {@link Scorer} for a term range defined by min/max ordinals. This is really + * just a common implementation detail of a couple different queries and not intended to be directly + * used (but must be public due to our package structure). You're probably better off looking at + * {@link org.apache.lucene.document.SortedSetDocValuesField#newSlowRangeQuery} or {@link + * org.apache.lucene.document.SortedSetDocValuesField#newSlowSetQuery}. + * + * @lucene.experimental + */ public class SortedSetDocValuesRangeScorer extends Scorer { final Scorer delegate; @@ -38,8 +45,9 @@ public class SortedSetDocValuesRangeScorer extends Scorer { ScoreMode scoreMode, float score, DocValuesSkipper skipper, - LeafReaderContext context) throws IOException { - delegate = setupScorer(field, values, minOrd, maxOrd, scoreMode, score, skipper, context); + LeafReader reader) + throws IOException { + delegate = setupScorer(field, values, minOrd, maxOrd, scoreMode, score, skipper, reader); } static Scorer setupScorer( @@ -50,21 +58,14 @@ public class SortedSetDocValuesRangeScorer extends Scorer { ScoreMode scoreMode, float score, DocValuesSkipper skipper, - LeafReaderContext context) throws IOException { - // no terms matched in this segment - if (minOrd > maxOrd - || (skipper != null - && (minOrd > skipper.maxValue() || maxOrd < skipper.minValue()))) { - return new ConstantScoreScorer(score, scoreMode, DocIdSetIterator.empty()); - } - + LeafReader reader) + throws IOException { // all terms matched in this segment if (skipper != null - && skipper.docCount() == context.reader().maxDoc() + && skipper.docCount() == reader.maxDoc() && skipper.minValue() >= minOrd && skipper.maxValue() <= maxOrd) { - return new ConstantScoreScorer( - score, scoreMode, DocIdSetIterator.all(skipper.docCount())); + return new ConstantScoreScorer(score, scoreMode, DocIdSetIterator.all(skipper.docCount())); } final SortedDocValues singleton = DocValues.unwrapSingleton(values); @@ -73,7 +74,7 @@ public class SortedSetDocValuesRangeScorer extends Scorer { if (skipper != null) { final DocIdSetIterator psIterator = getDocIdSetIteratorOrNullForPrimarySort( - context.reader(), field, singleton, skipper, minOrd, maxOrd); + reader, field, singleton, skipper, minOrd, maxOrd); if (psIterator != null) { return new ConstantScoreScorer(score, scoreMode, psIterator); }