Add Intervals.noIntervals() method (#13389)

Parsers may sometimes want to create an IntervalsSource that returns no
intervals.  This adds a new factory method to `Intervals` that will create one,
and changes `IntervalBuilder` to use it in place of its custom empty intervals
source.
This commit is contained in:
Alan Woodward 2024-05-21 09:22:44 +01:00 committed by GitHub
parent aac856a831
commit 92420d345a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 19 additions and 109 deletions

View File

@ -295,6 +295,9 @@ Improvements
* GITHUB#13362: Add sub query explanations to DisjunctionMaxQuery, if the overall query didn't match. (Tim Grein) * GITHUB#13362: Add sub query explanations to DisjunctionMaxQuery, if the overall query didn't match. (Tim Grein)
* GITHUB#13385: Add Intervals.noIntervals() method to produce an empty IntervalsSource.
(Aniketh Jain, Uwe Schindler, Alan Woodward))
Optimizations Optimizations
--------------------- ---------------------
@ -390,7 +393,6 @@ Other
* GITHUB#13077: Add public getter for SynonymQuery#field (Andrey Bozhko) * GITHUB#13077: Add public getter for SynonymQuery#field (Andrey Bozhko)
* GITHUB#13385: Make NO_INTERVALS source as public to be used by Lucene clients instead of creating clones themselves (Aniketh Jain)
======================== Lucene 9.10.0 ======================= ======================== Lucene 9.10.0 =======================

View File

@ -41,8 +41,6 @@ package org.apache.lucene.queries.intervals;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.lucene.analysis.CachingTokenFilter; import org.apache.lucene.analysis.CachingTokenFilter;
@ -50,9 +48,7 @@ import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionLengthAttribute; import org.apache.lucene.analysis.tokenattributes.PositionLengthAttribute;
import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute; import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.QueryVisitor;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.graph.GraphTokenStreamFiniteStrings; import org.apache.lucene.util.graph.GraphTokenStreamFiniteStrings;
@ -66,6 +62,10 @@ import org.apache.lucene.util.graph.GraphTokenStreamFiniteStrings;
* "https://github.com/elastic/elasticsearch/blob/7.10/server/src/main/java/org/elasticsearch/index/query/IntervalBuilder.java" * "https://github.com/elastic/elasticsearch/blob/7.10/server/src/main/java/org/elasticsearch/index/query/IntervalBuilder.java"
*/ */
final class IntervalBuilder { final class IntervalBuilder {
private static final IntervalsSource NO_INTERVALS =
Intervals.noIntervals("No terms in analyzed text");
static IntervalsSource analyzeText(CachingTokenFilter stream, int maxGaps, boolean ordered) static IntervalsSource analyzeText(CachingTokenFilter stream, int maxGaps, boolean ordered)
throws IOException { throws IOException {
assert stream != null; assert stream != null;
@ -235,94 +235,4 @@ final class IntervalBuilder {
} }
return clauses; return clauses;
} }
public static final IntervalsSource NO_INTERVALS =
new IntervalsSource() {
@Override
public IntervalIterator intervals(String field, LeafReaderContext ctx) {
return new IntervalIterator() {
boolean exhausted = false;
@Override
public int start() {
return NO_MORE_INTERVALS;
}
@Override
public int end() {
return NO_MORE_INTERVALS;
}
@Override
public int gaps() {
throw new UnsupportedOperationException();
}
@Override
public int nextInterval() {
return NO_MORE_INTERVALS;
}
@Override
public float matchCost() {
return 0;
}
@Override
public int docID() {
return exhausted ? NO_MORE_DOCS : -1;
}
@Override
public int nextDoc() {
exhausted = true;
return NO_MORE_DOCS;
}
@Override
public int advance(int target) {
exhausted = true;
return NO_MORE_DOCS;
}
@Override
public long cost() {
return 0;
}
};
}
@Override
public IntervalMatchesIterator matches(String field, LeafReaderContext ctx, int doc) {
return null;
}
@Override
public void visit(String field, QueryVisitor visitor) {}
@Override
public int minExtent() {
return 0;
}
@Override
public Collection<IntervalsSource> pullUpDisjunctions() {
return Collections.emptyList();
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object other) {
return other == this;
}
@Override
public String toString() {
return "no_match";
}
};
} }

View File

@ -500,6 +500,15 @@ public final class Intervals {
Intervals.extend(new OffsetIntervalsSource(reference, false), 0, Integer.MAX_VALUE)); Intervals.extend(new OffsetIntervalsSource(reference, false), 0, Integer.MAX_VALUE));
} }
/**
* Returns a source that produces no intervals
*
* @param reason A reason string that will appear in the toString output of this source
*/
public static IntervalsSource noIntervals(String reason) {
return new NoMatchIntervalsSource(reason);
}
/** /**
* Returns intervals that correspond to tokens from a {@link TokenStream} returned for {@code * Returns intervals that correspond to tokens from a {@link TokenStream} returned for {@code
* text} by applying the provided {@link Analyzer} as if {@code text} was the content of the given * text} by applying the provided {@link Analyzer} as if {@code text} was the content of the given

View File

@ -46,7 +46,6 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.analysis.CannedTokenStream; import org.apache.lucene.tests.analysis.CannedTokenStream;
import org.apache.lucene.tests.analysis.Token; import org.apache.lucene.tests.analysis.Token;
@ -115,7 +114,7 @@ public class TestIntervalBuilder extends LuceneTestCase {
public void testEmptyTokenStream() throws IOException { public void testEmptyTokenStream() throws IOException {
CannedTokenStream ts = new CannedTokenStream(); CannedTokenStream ts = new CannedTokenStream();
IntervalsSource source = IntervalBuilder.analyzeText(new CachingTokenFilter(ts), 0, true); IntervalsSource source = IntervalBuilder.analyzeText(new CachingTokenFilter(ts), 0, true);
assertSame(IntervalBuilder.NO_INTERVALS, source); assertEquals(Intervals.noIntervals("No terms in analyzed text"), source);
} }
public void testSimpleSynonyms() throws IOException { public void testSimpleSynonyms() throws IOException {
@ -235,18 +234,8 @@ public class TestIntervalBuilder extends LuceneTestCase {
IndexReader reader = DirectoryReader.open(directory); IndexReader reader = DirectoryReader.open(directory);
LeafReaderContext ctx = reader.leaves().get(0); LeafReaderContext ctx = reader.leaves().get(0);
{ IntervalIterator it = source.intervals("field", ctx);
IntervalIterator it = source.intervals("field", ctx); assertNull(it);
assertEquals(-1, it.docID());
it.nextDoc();
assertEquals(DocIdSetIterator.NO_MORE_DOCS, it.docID());
}
{
IntervalIterator it = source.intervals("field", ctx);
assertEquals(-1, it.docID());
it.advance(1);
assertEquals(DocIdSetIterator.NO_MORE_DOCS, it.docID());
}
reader.close(); reader.close();
directory.close(); directory.close();