mirror of
https://github.com/apache/lucene.git
synced 2025-02-08 11:05:29 +00:00
LUCENE-7337: empty boolean query now rewrites to MatchNoDocsQuery instead of vice/versa
This commit is contained in:
parent
5e2f340cfa
commit
a3fc7efbcc
@ -50,6 +50,10 @@ Improvements
|
||||
* LUCENE-7345: RAMDirectory now enforces write-once files as well
|
||||
(Robert Muir, Mike McCandless)
|
||||
|
||||
* LUCENE-7337: MatchNoDocsQuery now scores with 0 normalization factor
|
||||
and empty boolean queries now rewrite to MatchNoDocsQuery instead of
|
||||
vice/versa (Jim Ferenczi via Mike McCandless)
|
||||
|
||||
Optimizations
|
||||
|
||||
* LUCENE-7330: Speed up conjunction queries. (Adrien Grand)
|
||||
|
@ -147,4 +147,4 @@ public class KNearestNeighborDocumentClassifier extends KNearestNeighborClassifi
|
||||
}
|
||||
return indexSearcher.search(mltQuery.build(), k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +228,10 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
|
||||
|
||||
@Override
|
||||
public Query rewrite(IndexReader reader) throws IOException {
|
||||
if (clauses.size() == 0) {
|
||||
return new MatchNoDocsQuery();
|
||||
}
|
||||
|
||||
// optimize 1-clause queries
|
||||
if (clauses.size() == 1) {
|
||||
BooleanClause c = clauses.get(0);
|
||||
|
@ -18,22 +18,62 @@ package org.apache.lucene.search;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.index.Term;
|
||||
|
||||
/**
|
||||
* A query that matches no documents.
|
||||
* A query that matches no documents.
|
||||
*/
|
||||
|
||||
public class MatchNoDocsQuery extends Query {
|
||||
@Override
|
||||
public Query rewrite(IndexReader reader) throws IOException {
|
||||
// Rewrite to an empty BooleanQuery so no Scorer or Weight is required
|
||||
return new BooleanQuery.Builder().build();
|
||||
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
|
||||
return new Weight(this) {
|
||||
@Override
|
||||
public void extractTerms(Set<Term> terms) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Explanation explain(LeafReaderContext context, int doc) throws IOException {
|
||||
return Explanation.noMatch("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scorer scorer(LeafReaderContext context) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getValueForNormalization() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void normalize(float norm, float boost) {
|
||||
}
|
||||
|
||||
/** Return the normalization factor for this weight. */
|
||||
protected final float queryNorm() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return the boost for this weight. */
|
||||
protected final float boost() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return the score produced by this {@link Weight}. */
|
||||
protected final float score() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(String field) {
|
||||
return "";
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,8 +55,8 @@ public class TestBoostQuery extends LuceneTestCase {
|
||||
IndexSearcher searcher = new IndexSearcher(new MultiReader());
|
||||
|
||||
// inner queries are rewritten
|
||||
Query q = new BoostQuery(new MatchNoDocsQuery(), 2);
|
||||
assertEquals(new BoostQuery(new BooleanQuery.Builder().build(), 2), searcher.rewrite(q));
|
||||
Query q = new BoostQuery(new BooleanQuery.Builder().build(), 2);
|
||||
assertEquals(new BoostQuery(new MatchNoDocsQuery(), 2), searcher.rewrite(q));
|
||||
|
||||
// boosts are merged
|
||||
q = new BoostQuery(new BoostQuery(new MatchAllDocsQuery(), 3), 2);
|
||||
|
@ -55,11 +55,7 @@ public class TestMatchNoDocsQuery extends LuceneTestCase {
|
||||
hits = is.search(new MatchNoDocsQuery(), 1000).scoreDocs;
|
||||
assertEquals(0, hits.length);
|
||||
|
||||
// A MatchNoDocsQuery rewrites to an empty BooleanQuery
|
||||
MatchNoDocsQuery mndq = new MatchNoDocsQuery();
|
||||
Query rewritten = mndq.rewrite(ir);
|
||||
assertTrue(rewritten instanceof BooleanQuery);
|
||||
assertEquals(0, ((BooleanQuery) rewritten).clauses().size());
|
||||
hits = is.search(mndq, 1000).scoreDocs;
|
||||
assertEquals(0, hits.length);
|
||||
|
||||
|
@ -196,9 +196,15 @@ public class TestMultiTermQueryRewrites extends LuceneTestCase {
|
||||
}
|
||||
assertEquals("The multi-segment case must produce same rewritten query", q1, q2);
|
||||
assertEquals("The multi-segment case with duplicates must produce same rewritten query", q1, q3);
|
||||
checkBooleanQueryBoosts((BooleanQuery) q1);
|
||||
checkBooleanQueryBoosts((BooleanQuery) q2);
|
||||
checkBooleanQueryBoosts((BooleanQuery) q3);
|
||||
if (q1 instanceof MatchNoDocsQuery) {
|
||||
assertTrue(q1 instanceof MatchNoDocsQuery);
|
||||
assertTrue(q3 instanceof MatchNoDocsQuery);
|
||||
} else {
|
||||
checkBooleanQueryBoosts((BooleanQuery) q1);
|
||||
checkBooleanQueryBoosts((BooleanQuery) q2);
|
||||
checkBooleanQueryBoosts((BooleanQuery) q3);
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
public void testBoosts() throws Exception {
|
||||
|
@ -96,8 +96,7 @@ public class TestWildcard extends LuceneTestCase {
|
||||
wq.setRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_REWRITE);
|
||||
assertMatches(searcher, wq, 0);
|
||||
Query q = searcher.rewrite(wq);
|
||||
assertTrue(q instanceof BooleanQuery);
|
||||
assertEquals(0, ((BooleanQuery) q).clauses().size());
|
||||
assertTrue(q instanceof MatchNoDocsQuery);
|
||||
reader.close();
|
||||
indexStore.close();
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ public class BoostingQueryTest extends LuceneTestCase {
|
||||
|
||||
public void testRewrite() throws IOException {
|
||||
IndexReader reader = new MultiReader();
|
||||
BoostingQuery q = new BoostingQuery(new MatchNoDocsQuery(), new MatchAllDocsQuery(), 3);
|
||||
BoostingQuery q = new BoostingQuery(new BooleanQuery.Builder().build(), new MatchAllDocsQuery(), 3);
|
||||
Query rewritten = new IndexSearcher(reader).rewrite(q);
|
||||
Query expectedRewritten = new BoostingQuery(new BooleanQuery.Builder().build(), new MatchAllDocsQuery(), 3);
|
||||
Query expectedRewritten = new BoostingQuery(new MatchNoDocsQuery(), new MatchAllDocsQuery(), 3);
|
||||
assertEquals(expectedRewritten, rewritten);
|
||||
assertSame(rewritten, rewritten.rewrite(reader));
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
@ -295,6 +296,12 @@ public class ComplexPhraseQueryParser extends QueryParser {
|
||||
allSpanClauses[i] = new SpanTermQuery(new Term(field,
|
||||
"Dummy clause because no terms found - must match nothing"));
|
||||
}
|
||||
} else if (qc instanceof MatchNoDocsQuery) {
|
||||
// Insert fake term e.g. phrase query was for "Fred Smithe*" and
|
||||
// there were no "Smithe*" terms - need to
|
||||
// prevent match on just "Fred".
|
||||
allSpanClauses[i] = new SpanTermQuery(new Term(field,
|
||||
"Dummy clause because no terms found - must match nothing"));
|
||||
} else {
|
||||
if (qc instanceof TermQuery) {
|
||||
TermQuery tq = (TermQuery) qc;
|
||||
|
Loading…
x
Reference in New Issue
Block a user