LUCENE-10635: Ensure test coverage for WANDScorer by using a test query (#1039)

This commit is contained in:
Zach Chen 2022-10-15 13:02:02 -07:00 committed by GitHub
parent ece8ea715c
commit 21e3f654fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 226 additions and 93 deletions

View File

@ -149,6 +149,8 @@ Other
* GITHUB#11834: Upgrade forbiddenapis to version 3.4. (Uwe Schindler)
* LUCENE-10635: Ensure test coverage for WANDScorer by using a test query. (Zach Chen, Adrien Grand)
======================== Lucene 9.4.0 =======================
API Changes

View File

@ -18,6 +18,8 @@ package org.apache.lucene.search;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
@ -108,15 +110,16 @@ public class TestWANDScorer extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
Query query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.build();
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.build());
Scorer scorer =
searcher
@ -170,13 +173,16 @@ public class TestWANDScorer extends LuceneTestCase {
query =
new BooleanQuery.Builder()
.add(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.build(),
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.FILTER)
.build();
@ -210,9 +216,17 @@ public class TestWANDScorer extends LuceneTestCase {
query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.MUST_NOT)
.build();
@ -275,16 +289,19 @@ public class TestWANDScorer extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
Query query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build();
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build());
Scorer scorer =
searcher
@ -360,12 +377,13 @@ public class TestWANDScorer extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
Query query =
new BooleanQuery.Builder()
.add(new TermQuery(new Term("foo", "A")), Occur.SHOULD)
.add(new TermQuery(new Term("foo", "B")), Occur.SHOULD)
.add(new TermQuery(new Term("foo", "C")), Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build();
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(new TermQuery(new Term("foo", "A")), Occur.SHOULD)
.add(new TermQuery(new Term("foo", "B")), Occur.SHOULD)
.add(new TermQuery(new Term("foo", "C")), Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build());
Scorer scorer =
searcher
@ -407,16 +425,19 @@ public class TestWANDScorer extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
Query query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build();
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build());
Scorer scorer =
searcher
@ -460,20 +481,21 @@ public class TestWANDScorer extends LuceneTestCase {
Query query =
new BooleanQuery.Builder()
.add(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build(),
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.FILTER)
.build();
@ -536,20 +558,21 @@ public class TestWANDScorer extends LuceneTestCase {
Query query =
new BooleanQuery.Builder()
.add(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build(),
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.FILTER)
.build();
@ -595,14 +618,23 @@ public class TestWANDScorer extends LuceneTestCase {
Query query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.MUST_NOT)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build();
Scorer scorer =
@ -663,14 +695,23 @@ public class TestWANDScorer extends LuceneTestCase {
Query query =
new BooleanQuery.Builder()
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD)
new WANDScorerQuery(
new BooleanQuery.Builder()
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2),
Occur.SHOULD)
.add(
new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))),
Occur.SHOULD)
.add(
new BoostQuery(
new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build()),
Occur.MUST)
.add(new TermQuery(new Term("foo", "C")), Occur.MUST_NOT)
.add(
new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "D"))), 4),
Occur.SHOULD)
.setMinimumNumberShouldMatch(2)
.build();
Scorer scorer =
@ -700,7 +741,10 @@ public class TestWANDScorer extends LuceneTestCase {
}
IndexReader reader = DirectoryReader.open(w);
w.close();
IndexSearcher searcher = newSearcher(reader);
// turn off concurrent search to avoid Random object used across threads resulting into
// RuntimeException, as WANDScorerQuery#createWeight has reference to this searcher,
// but will be called during searching
IndexSearcher searcher = newSearcher(reader, true, true, false);
for (int iter = 0; iter < 100; ++iter) {
int start = random().nextInt(10);
@ -710,7 +754,7 @@ public class TestWANDScorer extends LuceneTestCase {
builder.add(
maybeWrap(new TermQuery(new Term("foo", Integer.toString(start + i)))), Occur.SHOULD);
}
Query query = builder.build();
Query query = new WANDScorerQuery(builder.build());
CheckHits.checkTopScores(random(), query, searcher);
@ -743,7 +787,10 @@ public class TestWANDScorer extends LuceneTestCase {
}
IndexReader reader = DirectoryReader.open(w);
w.close();
IndexSearcher searcher = newSearcher(reader);
// turn off concurrent search to avoid Random object used across threads resulting into
// RuntimeException, as WANDScorerQuery#createWeight has reference to this searcher,
// but will be called during searching
IndexSearcher searcher = newSearcher(reader, true, true, false);
for (int iter = 0; iter < 100; ++iter) {
int start = random().nextInt(10);
@ -758,7 +805,7 @@ public class TestWANDScorer extends LuceneTestCase {
0f)),
Occur.SHOULD);
}
Query query = builder.build();
Query query = new WANDScorerQuery(builder.build());
CheckHits.checkTopScores(random(), query, searcher);
@ -800,7 +847,10 @@ public class TestWANDScorer extends LuceneTestCase {
}
IndexReader reader = DirectoryReader.open(w);
w.close();
IndexSearcher searcher = newSearcher(reader);
// turn off concurrent search to avoid Random object used across threads resulting into
// RuntimeException, as WANDScorerQuery#createWeight has reference to this searcher,
// but will be called during searching
IndexSearcher searcher = newSearcher(reader, true, true, false);
for (int iter = 0; iter < 100; ++iter) {
int start = random().nextInt(10);
@ -815,7 +865,7 @@ public class TestWANDScorer extends LuceneTestCase {
}
builder.add(query, Occur.SHOULD);
}
Query query = builder.build();
Query query = new WANDScorerQuery(builder.build());
CheckHits.checkTopScores(random(), query, searcher);
@ -947,4 +997,85 @@ public class TestWANDScorer extends LuceneTestCase {
};
}
}
private static class WANDScorerQuery extends Query {
private final BooleanQuery query;
private WANDScorerQuery(BooleanQuery query) {
assert query.clauses().size() == query.getClauses(Occur.SHOULD).size()
: "This test utility query is only used to create WANDScorer for disjunctions.";
this.query = query;
}
@Override
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost)
throws IOException {
return new Weight(query) {
@Override
public Explanation explain(LeafReaderContext context, int doc) throws IOException {
// no-ops
return null;
}
@Override
public Scorer scorer(LeafReaderContext context) throws IOException {
BooleanWeight weight = (BooleanWeight) query.createWeight(searcher, scoreMode, boost);
List<Scorer> optionalScorers =
weight.weightedClauses.stream()
.map(wc -> wc.weight)
.map(
w -> {
try {
return w.scorerSupplier(context);
} catch (IOException e) {
throw new AssertionError(e);
}
})
.filter(Objects::nonNull)
.map(
ss -> {
try {
return ss.get(Long.MAX_VALUE);
} catch (IOException e) {
throw new AssertionError(e);
}
})
.toList();
if (optionalScorers.size() > 0) {
return new WANDScorer(
weight, optionalScorers, query.getMinimumNumberShouldMatch(), scoreMode);
} else {
return weight.scorer(context);
}
}
@Override
public boolean isCacheable(LeafReaderContext ctx) {
return false;
}
};
}
@Override
public String toString(String field) {
return "WANDScorerQuery";
}
@Override
public void visit(QueryVisitor visitor) {
// no-ops
}
@Override
public boolean equals(Object other) {
return sameClassAs(other) && query.equals(((TestWANDScorer.WANDScorerQuery) other).query);
}
@Override
public int hashCode() {
return 31 * classHash() + query.hashCode();
}
}
}