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
This commit is contained in:
Tim Jones 2004-04-21 19:18:44 +00:00
parent 96e1b41127
commit 30ef9989dc
2 changed files with 239 additions and 0 deletions

View File

@ -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.
*
* <p>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.
*
* <p>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 <code>null</code>.
* @param filter Filter to apply to query results, cannot be <code>null</code>.
*/
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 <code>o</code> 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();
}
}

View File

@ -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.
*
* <p>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);
}
}