From 30ef9989dc6e8ff5334bb853f3de764e5f8547d5 Mon Sep 17 00:00:00 2001 From: Tim Jones Date: Wed, 21 Apr 2004 19:18:44 +0000 Subject: [PATCH] new Query which applies a Filter to another Query git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@150308 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/lucene/search/FilteredQuery.java | 121 ++++++++++++++++++ .../lucene/search/TestFilteredQuery.java | 118 +++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 src/java/org/apache/lucene/search/FilteredQuery.java create mode 100644 src/test/org/apache/lucene/search/TestFilteredQuery.java 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