mirror of https://github.com/apache/lucene.git
LUCENE-9744: NPE on a degenerate query in MinimumShouldMatchIntervalsSource$MinimumMatchesIterator.getSubMatches() (#2323)
This commit is contained in:
parent
80803eb9ad
commit
077f8ccf70
|
@ -288,7 +288,9 @@ Optimizations
|
|||
|
||||
Bug Fixes
|
||||
---------------------
|
||||
(No changes)
|
||||
|
||||
* LUCENE-9744: NPE on a degenerate query in MinimumShouldMatchIntervalsSource
|
||||
$MinimumMatchesIterator.getSubMatches(). (Alan Woodward)
|
||||
|
||||
Other
|
||||
---------------------
|
||||
|
|
|
@ -404,6 +404,16 @@ public final class Intervals {
|
|||
* Return intervals that span combinations of intervals from {@code minShouldMatch} of the sources
|
||||
*/
|
||||
public static IntervalsSource atLeast(int minShouldMatch, IntervalsSource... sources) {
|
||||
if (minShouldMatch == sources.length) {
|
||||
return unordered(sources);
|
||||
}
|
||||
if (minShouldMatch > sources.length) {
|
||||
return new NoMatchIntervalsSource(
|
||||
"Too few sources to match minimum of ["
|
||||
+ minShouldMatch
|
||||
+ "]: "
|
||||
+ Arrays.toString(sources));
|
||||
}
|
||||
return new MinimumShouldMatchIntervalsSource(sources, minShouldMatch);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ class MinimumShouldMatchIntervalsSource extends IntervalsSource {
|
|||
private final int minShouldMatch;
|
||||
|
||||
MinimumShouldMatchIntervalsSource(IntervalsSource[] sources, int minShouldMatch) {
|
||||
assert minShouldMatch < sources.length;
|
||||
this.sources = sources;
|
||||
this.minShouldMatch = minShouldMatch;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.queries.intervals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.search.QueryVisitor;
|
||||
|
||||
/** A source returning no matches */
|
||||
class NoMatchIntervalsSource extends IntervalsSource {
|
||||
final String reason;
|
||||
|
||||
NoMatchIntervalsSource(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntervalIterator intervals(String field, LeafReaderContext ctx) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntervalMatchesIterator matches(String field, LeafReaderContext ctx, int doc)
|
||||
throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String field, QueryVisitor visitor) {}
|
||||
|
||||
@Override
|
||||
public int minExtent() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<IntervalsSource> pullUpDisjunctions() {
|
||||
return Collections.singleton(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NoMatchIntervalsSource that = (NoMatchIntervalsSource) o;
|
||||
return Objects.equals(reason, that.reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NOMATCH(" + reason + ")";
|
||||
}
|
||||
}
|
|
@ -756,6 +756,27 @@ public class TestIntervals extends LuceneTestCase {
|
|||
assertEquals(3, source.minExtent());
|
||||
}
|
||||
|
||||
public void testDegenerateMinShouldMatch() throws IOException {
|
||||
IntervalsSource source =
|
||||
Intervals.ordered(
|
||||
Intervals.atLeast(1, Intervals.term("interest")),
|
||||
Intervals.atLeast(1, Intervals.term("anyone")));
|
||||
|
||||
MatchesIterator mi = getMatches(source, 0, "field1");
|
||||
assertMatch(mi, 2, 4, 11, 29);
|
||||
MatchesIterator subs = mi.getSubMatches();
|
||||
assertNotNull(subs);
|
||||
assertMatch(subs, 2, 2, 11, 19);
|
||||
assertMatch(subs, 4, 4, 23, 29);
|
||||
assertFalse(subs.next());
|
||||
assertFalse(mi.next());
|
||||
}
|
||||
|
||||
public void testNoMatchMinShouldMatch() throws IOException {
|
||||
IntervalsSource source = Intervals.atLeast(4, Intervals.term("a"), Intervals.term("b"));
|
||||
checkIntervals(source, "field", 0, new int[][] {});
|
||||
}
|
||||
|
||||
public void testDefinedGaps() throws IOException {
|
||||
IntervalsSource source =
|
||||
Intervals.phrase(
|
||||
|
|
|
@ -111,4 +111,13 @@ public class TestSimplifications extends LuceneTestCase {
|
|||
Intervals.term("a"), Intervals.term("b"), Intervals.term("c"), Intervals.term("d")),
|
||||
actual);
|
||||
}
|
||||
|
||||
public void testMinShouldMatchSimplifications() {
|
||||
IntervalsSource expected = Intervals.unordered(Intervals.term("a"), Intervals.term("b"));
|
||||
assertEquals(expected, Intervals.atLeast(2, Intervals.term("a"), Intervals.term("b")));
|
||||
|
||||
assertEquals(
|
||||
"NOMATCH(Too few sources to match minimum of [3]: [a, b])",
|
||||
Intervals.atLeast(3, Intervals.term("a"), Intervals.term("b")).toString());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue