mirror of https://github.com/apache/lucene.git
LUCENE-10412: Improve handling of MatchNoDocsQuery in rewrites. (#664)
This commit is contained in:
parent
2183756f1c
commit
69d3a1d6af
|
@ -204,6 +204,9 @@ Optimizations
|
||||||
* LUCENE-10367: Optimize CoveringQuery for the case when the minimum number of
|
* LUCENE-10367: Optimize CoveringQuery for the case when the minimum number of
|
||||||
matching clauses is a constant. (LuYunCheng via Adrien Grand)
|
matching clauses is a constant. (LuYunCheng via Adrien Grand)
|
||||||
|
|
||||||
|
* LUCENE-10412: More `Query#rewrite` optimizations for MatchNoDocsQuery.
|
||||||
|
(Adrien Grand)
|
||||||
|
|
||||||
Changes in runtime behavior
|
Changes in runtime behavior
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
|
@ -275,10 +275,22 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
|
||||||
for (BooleanClause clause : this) {
|
for (BooleanClause clause : this) {
|
||||||
Query query = clause.getQuery();
|
Query query = clause.getQuery();
|
||||||
Query rewritten = query.rewrite(reader);
|
Query rewritten = query.rewrite(reader);
|
||||||
if (rewritten != query) {
|
if (rewritten != query || query.getClass() == MatchNoDocsQuery.class) {
|
||||||
// rewrite clause
|
// rewrite clause
|
||||||
actuallyRewritten = true;
|
actuallyRewritten = true;
|
||||||
|
if (rewritten.getClass() == MatchNoDocsQuery.class) {
|
||||||
|
switch (clause.getOccur()) {
|
||||||
|
case SHOULD:
|
||||||
|
case MUST_NOT:
|
||||||
|
// the clause can be safely ignored
|
||||||
|
break;
|
||||||
|
case MUST:
|
||||||
|
case FILTER:
|
||||||
|
return rewritten;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
builder.add(rewritten, clause.getOccur());
|
builder.add(rewritten, clause.getOccur());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// leave as-is
|
// leave as-is
|
||||||
builder.add(clause);
|
builder.add(clause);
|
||||||
|
|
|
@ -85,6 +85,11 @@ public final class BoostQuery extends Query {
|
||||||
return new BoostQuery(in.query, boost * in.boost);
|
return new BoostQuery(in.query, boost * in.boost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rewritten.getClass() == MatchNoDocsQuery.class) {
|
||||||
|
// bubble up MatchNoDocsQuery
|
||||||
|
return rewritten;
|
||||||
|
}
|
||||||
|
|
||||||
if (boost == 0f && rewritten.getClass() != ConstantScoreQuery.class) {
|
if (boost == 0f && rewritten.getClass() != ConstantScoreQuery.class) {
|
||||||
// so that we pass needScores=false
|
// so that we pass needScores=false
|
||||||
return new BoostQuery(new ConstantScoreQuery(rewritten), 0f);
|
return new BoostQuery(new ConstantScoreQuery(rewritten), 0f);
|
||||||
|
|
|
@ -43,6 +43,11 @@ public final class ConstantScoreQuery extends Query {
|
||||||
public Query rewrite(IndexReader reader) throws IOException {
|
public Query rewrite(IndexReader reader) throws IOException {
|
||||||
Query rewritten = query.rewrite(reader);
|
Query rewritten = query.rewrite(reader);
|
||||||
|
|
||||||
|
if (rewritten.getClass() == MatchNoDocsQuery.class) {
|
||||||
|
// bubble up MatchNoDocsQuery
|
||||||
|
return rewritten;
|
||||||
|
}
|
||||||
|
|
||||||
if (rewritten != query) {
|
if (rewritten != query) {
|
||||||
return new ConstantScoreQuery(rewritten);
|
return new ConstantScoreQuery(rewritten);
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,4 +663,54 @@ public class TestBooleanRewrites extends LuceneTestCase {
|
||||||
w.close();
|
w.close();
|
||||||
dir.close();
|
dir.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testShouldMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
BooleanQuery query =
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term("foo", "bar")), Occur.SHOULD)
|
||||||
|
.add(new MatchNoDocsQuery(), Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(new TermQuery(new Term("foo", "bar")), searcher.rewrite(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMustNotMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
BooleanQuery query =
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term("foo", "bar")), Occur.SHOULD)
|
||||||
|
.add(new MatchNoDocsQuery(), Occur.MUST_NOT)
|
||||||
|
.build();
|
||||||
|
assertEquals(new TermQuery(new Term("foo", "bar")), searcher.rewrite(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMustMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
BooleanQuery query =
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term("foo", "bar")), Occur.MUST)
|
||||||
|
.add(new MatchNoDocsQuery(), Occur.MUST)
|
||||||
|
.build();
|
||||||
|
assertEquals(new MatchNoDocsQuery(), searcher.rewrite(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFilterMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
BooleanQuery query =
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term("foo", "bar")), Occur.MUST)
|
||||||
|
.add(new MatchNoDocsQuery(), Occur.FILTER)
|
||||||
|
.build();
|
||||||
|
assertEquals(new MatchNoDocsQuery(), searcher.rewrite(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEmptyBoolean() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
BooleanQuery query = new BooleanQuery.Builder().build();
|
||||||
|
assertEquals(new MatchNoDocsQuery(), searcher.rewrite(query));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ public class TestBoostQuery extends LuceneTestCase {
|
||||||
IndexSearcher searcher = new IndexSearcher(new MultiReader());
|
IndexSearcher searcher = new IndexSearcher(new MultiReader());
|
||||||
|
|
||||||
// inner queries are rewritten
|
// inner queries are rewritten
|
||||||
Query q = new BoostQuery(new BooleanQuery.Builder().build(), 2);
|
Query q = new BoostQuery(new PhraseQuery("foo", "bar"), 2);
|
||||||
assertEquals(new BoostQuery(new MatchNoDocsQuery(), 2), searcher.rewrite(q));
|
assertEquals(new BoostQuery(new TermQuery(new Term("foo", "bar")), 2), searcher.rewrite(q));
|
||||||
|
|
||||||
// boosts are merged
|
// boosts are merged
|
||||||
q = new BoostQuery(new BoostQuery(new MatchAllDocsQuery(), 3), 2);
|
q = new BoostQuery(new BoostQuery(new MatchAllDocsQuery(), 3), 2);
|
||||||
|
@ -85,4 +85,11 @@ public class TestBoostQuery extends LuceneTestCase {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new BoostQuery(new ConstantScoreQuery(new MatchAllDocsQuery()), 0), searcher.rewrite(q));
|
new BoostQuery(new ConstantScoreQuery(new MatchAllDocsQuery()), 0), searcher.rewrite(q));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testRewriteBubblesUpMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
Query query = new BoostQuery(new MatchNoDocsQuery(), 2f);
|
||||||
|
assertEquals(new MatchNoDocsQuery(), searcher.rewrite(query));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.document.Document;
|
||||||
import org.apache.lucene.document.Field;
|
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.MultiReader;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanClause.Occur;
|
import org.apache.lucene.search.BooleanClause.Occur;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
|
@ -254,4 +255,11 @@ public class TestConstantScoreQuery extends LuceneTestCase {
|
||||||
w.close();
|
w.close();
|
||||||
dir.close();
|
dir.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testRewriteBubblesUpMatchNoDocsQuery() throws IOException {
|
||||||
|
IndexSearcher searcher = newSearcher(new MultiReader());
|
||||||
|
|
||||||
|
Query query = new ConstantScoreQuery(new MatchNoDocsQuery());
|
||||||
|
assertEquals(new MatchNoDocsQuery(), searcher.rewrite(query));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class TestMatchNoDocsQuery extends LuceneTestCase {
|
||||||
hits = searcher.search(query, 1000).scoreDocs;
|
hits = searcher.search(query, 1000).scoreDocs;
|
||||||
Query rewrite = query.rewrite(ir);
|
Query rewrite = query.rewrite(ir);
|
||||||
assertEquals(1, hits.length);
|
assertEquals(1, hits.length);
|
||||||
assertEquals(rewrite.toString(), "key:one MatchNoDocsQuery(\"field not found\")");
|
assertEquals(rewrite.toString(), "key:one");
|
||||||
|
|
||||||
iw.close();
|
iw.close();
|
||||||
ir.close();
|
ir.close();
|
||||||
|
|
Loading…
Reference in New Issue