From 4d6df6a4806876802f78f08cf541f4e7ac212a68 Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Wed, 4 Mar 2015 09:23:48 +0000 Subject: [PATCH] LUCENE-6304: Add MatchNoDocsQuery. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1663899 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 3 + .../lucene/search/MatchNoDocsQuery.java | 47 ++++++++++ .../java/org/apache/lucene/search/Query.java | 5 +- .../lucene/search/TestMatchNoDocsQuery.java | 86 +++++++++++++++++++ .../queryparser/simple/SimpleQueryParser.java | 3 +- .../simple/TestSimpleQueryParser.java | 5 +- 6 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java create mode 100644 lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 0b0157abb54..8305ca6acb3 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -54,6 +54,9 @@ New Features * LUCENE-6303: Added filter caching baked into IndexSearcher and enabled by default. (Adrien Grand) +* LUCENE-6304: Added a new MatchNoDocsQuery that matches no documents. + (Lee Hinman via Adrien Grand) + Bug Fixes * LUCENE-6249: StandardQueryParser doesn't support pure negative clauses. diff --git a/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java new file mode 100644 index 00000000000..97c1b15d455 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java @@ -0,0 +1,47 @@ +package org.apache.lucene.search; + +/* + * 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. + */ + +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; +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.ToStringUtils; + +/** + * 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(); + } + + @Override + public String toString(String field) { + StringBuilder buffer = new StringBuilder(); + buffer.append("_none_"); + buffer.append(ToStringUtils.boost(getBoost())); + return buffer.toString(); + } +} diff --git a/lucene/core/src/java/org/apache/lucene/search/Query.java b/lucene/core/src/java/org/apache/lucene/search/Query.java index 3311f03f998..027a39ed9a5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Query.java +++ b/lucene/core/src/java/org/apache/lucene/search/Query.java @@ -112,10 +112,7 @@ public abstract class Query implements Cloneable { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Float.floatToIntBits(boost); - return result; + return Float.floatToIntBits(getBoost()) ^ getClass().hashCode(); } @Override diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java new file mode 100644 index 00000000000..b0dbc24917e --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java @@ -0,0 +1,86 @@ +/* + * 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.search; + +import java.io.IOException; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.MockAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.store.Directory; + +import org.apache.lucene.util.LuceneTestCase; + +/** + * Tests MatchNoDocsQuery. + */ +public class TestMatchNoDocsQuery extends LuceneTestCase { + private Analyzer analyzer; + + @Override + public void setUp() throws Exception { + super.setUp(); + analyzer = new MockAnalyzer(random()); + } + + public void testQuery() throws Exception { + Directory dir = newDirectory(); + IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(analyzer).setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy())); + addDoc("one", iw); + addDoc("two", iw); + addDoc("three four", iw); + IndexReader ir = DirectoryReader.open(iw, true); + + IndexSearcher is = newSearcher(ir); + ScoreDoc[] hits; + + 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); + + iw.close(); + ir.close(); + dir.close(); + } + + public void testEquals() { + Query q1 = new MatchNoDocsQuery(); + Query q2 = new MatchNoDocsQuery(); + assertTrue(q1.equals(q2)); + QueryUtils.check(q1); + } + + private void addDoc(String text, IndexWriter iw) throws IOException { + Document doc = new Document(); + Field f = newTextField("key", text, Field.Store.YES); + doc.add(f); + iw.addDocument(doc); + } + +} diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/simple/SimpleQueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/simple/SimpleQueryParser.java index f5c23fef52e..0d614656be4 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/simple/SimpleQueryParser.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/simple/SimpleQueryParser.java @@ -23,6 +23,7 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.QueryBuilder; @@ -149,7 +150,7 @@ public class SimpleQueryParser extends QueryBuilder { State state = new State(data, buffer, 0, data.length); parseSubQuery(state); if (state.top == null) { - return new BooleanQuery(); + return new MatchNoDocsQuery(); } else { return state.top; } diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/simple/TestSimpleQueryParser.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/simple/TestSimpleQueryParser.java index 42158d50a2c..6bf7788a39d 100644 --- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/simple/TestSimpleQueryParser.java +++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/simple/TestSimpleQueryParser.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; @@ -273,7 +274,7 @@ public class TestSimpleQueryParser extends LuceneTestCase { } public void testGarbageEmpty() throws Exception { - BooleanQuery expected = new BooleanQuery(); + MatchNoDocsQuery expected = new MatchNoDocsQuery(); assertEquals(expected, parse("")); assertEquals(expected, parse(" ")); @@ -645,4 +646,4 @@ public class TestSimpleQueryParser extends LuceneTestCase { parseKeyword(sb.toString(), TestUtil.nextInt(random(), 0, 1024)); // no exception } } -} \ No newline at end of file +}