diff --git a/src/java/org/apache/lucene/search/FilteredQuery.java b/src/java/org/apache/lucene/search/FilteredQuery.java new file mode 100644 index 00000000000..816a0d41edc --- /dev/null +++ b/src/java/org/apache/lucene/search/FilteredQuery.java @@ -0,0 +1,121 @@ +package org.apache.lucene.search; + +/** + * Copyright 2004 The Apache Software Foundation + * + * Licensed 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 org.apache.lucene.index.IndexReader; +import java.io.IOException; +import java.util.BitSet; + + +/** + * A query that applies a filter to the results of another query. + * + *
Note: the bits are retrieved from the filter each time this + * query is used in a search - use a CachingWrapperFilter to avoid + * regenerating the bits every time. + * + *
Created: Apr 20, 2004 8:58:29 AM
+ *
+ * @author Tim Jones
+ * @since 1.4
+ * @version $Id$
+ * @see CachingWrapperFilter
+ */
+public class FilteredQuery
+extends Query {
+
+ Query query;
+ Filter filter;
+
+ /**
+ * Constructs a new query which applies a filter to the results of the original query.
+ * Filter.bits() will be called every time this query is used in a search.
+ * @param query Query to be filtered, cannot be null
.
+ * @param filter Filter to apply to query results, cannot be null
.
+ */
+ public FilteredQuery (Query query, Filter filter) {
+ this.query = query;
+ this.filter = filter;
+ }
+
+ /**
+ * Returns a Weight that applies the filter to the enclosed query's Weight.
+ * This is accomplished by overriding the Scorer returned by the Weight.
+ */
+ protected Weight createWeight (final Searcher searcher) {
+ final Weight weight = query.createWeight (searcher);
+ return new Weight() {
+
+ // pass these methods through to enclosed query's weight
+ public float getValue() { return weight.getValue(); }
+ public float sumOfSquaredWeights() throws IOException { return weight.sumOfSquaredWeights(); }
+ public void normalize (float v) { weight.normalize(v); }
+ public Explanation explain (IndexReader ir, int i) throws IOException { return weight.explain (ir, i); }
+
+ // return this query
+ public Query getQuery() { return FilteredQuery.this; }
+
+ // return a scorer that overrides the enclosed query's score if
+ // the given hit has been filtered out.
+ public Scorer scorer (IndexReader indexReader) throws IOException {
+ final Scorer scorer = weight.scorer (indexReader);
+ final BitSet bitset = filter.bits (indexReader);
+ return new Scorer (query.getSimilarity (searcher)) {
+
+ // pass these methods through to the enclosed scorer
+ public boolean next() throws IOException { return scorer.next(); }
+ public int doc() { return scorer.doc(); }
+ public boolean skipTo (int i) throws IOException { return scorer.skipTo(i); }
+
+ // if the document has been filtered out, set score to 0.0
+ public float score() throws IOException {
+ return (bitset.get(scorer.doc())) ? scorer.score() : 0.0f;
+ }
+
+ // add an explanation about whether the document was filtered
+ public Explanation explain (int i) throws IOException {
+ Explanation exp = scorer.explain (i);
+ if (bitset.get(i))
+ exp.setDescription ("allowed by filter: "+exp.getDescription());
+ else
+ exp.setDescription ("removed by filter: "+exp.getDescription());
+ return exp;
+ }
+ };
+ }
+ };
+ }
+
+ /** Prints a user-readable version of this query. */
+ public String toString (String s) {
+ return "filtered("+query.toString()+")";
+ }
+
+ /** Returns true iff o
is equal to this. */
+ public boolean equals(Object o) {
+ if (o instanceof FilteredQuery) {
+ FilteredQuery fq = (FilteredQuery) o;
+ return (query.equals(fq.query) && filter.equals(fq.filter));
+ }
+ return false;
+ }
+
+ /** Returns a hash code value for this object. */
+ public int hashCode() {
+ return query.hashCode() ^ filter.hashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/test/org/apache/lucene/search/TestFilteredQuery.java b/src/test/org/apache/lucene/search/TestFilteredQuery.java
new file mode 100644
index 00000000000..d14b76a5c67
--- /dev/null
+++ b/src/test/org/apache/lucene/search/TestFilteredQuery.java
@@ -0,0 +1,118 @@
+package org.apache.lucene.search;
+
+/**
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed 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 junit.framework.TestCase;
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.store.RAMDirectory;
+import java.util.BitSet;
+import java.io.IOException;
+
+
+/**
+ * FilteredQuery JUnit tests.
+ *
+ *
Created: Apr 21, 2004 1:21:46 PM + * + * @author Tim Jones + * @version $Id$ + * @since 1.4 + */ +public class TestFilteredQuery +extends TestCase { + + private IndexSearcher searcher; + private RAMDirectory directory; + private Query query; + private Filter filter; + + public void setUp() + throws Exception { + directory = new RAMDirectory(); + IndexWriter writer = new IndexWriter (directory, new WhitespaceAnalyzer(), true); + + Document doc = new Document(); + doc.add (Field.Text ("field", "one two three four five")); + doc.add (Field.Text ("sorter", "b")); + writer.addDocument (doc); + + doc = new Document(); + doc.add (Field.Text ("field", "one two three four")); + doc.add (Field.Text ("sorter", "d")); + writer.addDocument (doc); + + doc = new Document(); + doc.add (Field.Text ("field", "one two three y")); + doc.add (Field.Text ("sorter", "a")); + writer.addDocument (doc); + + doc = new Document(); + doc.add (Field.Text ("field", "one two x")); + doc.add (Field.Text ("sorter", "c")); + writer.addDocument (doc); + + writer.optimize (); + writer.close (); + + searcher = new IndexSearcher (directory); + query = new TermQuery (new Term ("field", "three")); + filter = new Filter() { + public BitSet bits (IndexReader reader) throws IOException { + BitSet bitset = new BitSet(5); + bitset.set (1); + bitset.set (3); + return bitset; + } + }; + } + + public void tearDown() + throws Exception { + searcher.close(); + directory.close(); + } + + public void testFilteredQuery() + throws Exception { + Query filteredquery = new FilteredQuery (query, filter); + Hits hits = searcher.search (filteredquery); + assertEquals (hits.length(), 1); + assertEquals (hits.id(0), 1); + + hits = searcher.search (filteredquery, new Sort("sorter")); + assertEquals (hits.length(), 1); + assertEquals (hits.id(0), 1); + + filteredquery = new FilteredQuery (new TermQuery (new Term ("field", "one")), filter); + hits = searcher.search (filteredquery); + assertEquals (hits.length(), 2); + + filteredquery = new FilteredQuery (new TermQuery (new Term ("field", "x")), filter); + hits = searcher.search (filteredquery); + assertEquals (hits.length(), 1); + assertEquals (hits.id(0), 3); + + filteredquery = new FilteredQuery (new TermQuery (new Term ("field", "y")), filter); + hits = searcher.search (filteredquery); + assertEquals (hits.length(), 0); + } +} \ No newline at end of file