LUCENE-6448: Make Filter a better Query citizen.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1675199 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Adrien Grand 2015-04-21 20:56:14 +00:00
parent ef4c9ffc06
commit 1422c4607f
27 changed files with 467 additions and 222 deletions

View File

@ -50,16 +50,22 @@ public class ConstantScoreQuery extends Query {
@Override
public Query rewrite(IndexReader reader) throws IOException {
Query sub = query;
if (sub instanceof QueryWrapperFilter) {
sub = ((QueryWrapperFilter) sub).getQuery();
Query rewritten = query.rewrite(reader);
if (rewritten.getClass() == getClass()) {
if (getBoost() != rewritten.getBoost()) {
rewritten = rewritten.clone();
rewritten.setBoost(getBoost());
}
return rewritten;
}
Query rewritten = sub.rewrite(reader);
if (rewritten != query) {
rewritten = new ConstantScoreQuery(rewritten);
rewritten.setBoost(this.getBoost());
return rewritten;
}
return this;
}

View File

@ -63,19 +63,6 @@ public abstract class Filter extends Query {
// Query compatibility
//
@Override
public boolean equals(Object that) {
// Query's default impl only compares boost but they do not matter in the
// case of filters since it does not influence scores
return this == that;
}
@Override
public int hashCode() {
// Query's default impl returns a hash of the boost but this is irrelevant to filters
return System.identityHashCode(this);
}
@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
return new Weight(this) {

View File

@ -327,27 +327,27 @@ public class FilteredQuery extends Query {
@Override
public Query rewrite(IndexReader reader) throws IOException {
if (filter instanceof QueryWrapperFilter) {
// In that case the filter does not implement random-access anyway so
// we want to take advantage of approximations
BooleanQuery rewritten = new BooleanQuery();
rewritten.add(query, Occur.MUST);
rewritten.add(((QueryWrapperFilter) filter).getQuery(), Occur.FILTER);
rewritten.setBoost(getBoost());
return rewritten;
}
final Query queryRewritten = query.rewrite(reader);
final Query filterRewritten = filter.rewrite(reader);
if (queryRewritten != query) {
// rewrite to a new FilteredQuery wrapping the rewritten query
final Query rewritten = new FilteredQuery(queryRewritten, filter, strategy);
rewritten.setBoost(this.getBoost());
return rewritten;
} else {
// nothing to rewrite, we are done!
return this;
if (queryRewritten != query || filterRewritten != filter) {
// rewrite to a new FilteredQuery wrapping the rewritten query/filter
if (filterRewritten instanceof Filter) {
final Query rewritten = new FilteredQuery(queryRewritten, (Filter) filterRewritten, strategy);
rewritten.setBoost(this.getBoost());
return rewritten;
} else {
// In that case the filter does not implement random-access anyway so
// we want to take advantage of approximations
BooleanQuery rewritten = new BooleanQuery();
rewritten.add(queryRewritten, Occur.MUST);
rewritten.add(filterRewritten, Occur.FILTER);
rewritten.setBoost(getBoost());
return rewritten;
}
}
// nothing to rewrite, we are done!
return this;
}
/** Returns this FilteredQuery's (unfiltered) Query */

View File

@ -81,13 +81,14 @@ public class QueryWrapperFilter extends Filter {
@Override
public boolean equals(Object o) {
if (!(o instanceof QueryWrapperFilter))
if (super.equals(o) == false) {
return false;
}
return this.query.equals(((QueryWrapperFilter)o).query);
}
@Override
public int hashCode() {
return query.hashCode() ^ 0x923F64B9;
return 31 * super.hashCode() + query.hashCode();
}
}

View File

@ -43,4 +43,17 @@ public class SingleDocTestFilter extends Filter {
public String toString(String field) {
return "SingleDocTestFilter(" + doc + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return doc == ((SingleDocTestFilter) obj).doc;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + doc;
}
}

View File

@ -153,6 +153,18 @@ public class TestConstantScoreQuery extends LuceneTestCase {
return in.toString(field);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return in.equals(((FilterWrapper) obj).in);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + in.hashCode();
}
}
public void testConstantScoreQueryAndFilter() throws Exception {

View File

@ -24,20 +24,20 @@ import java.util.Random;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.FilteredQuery.FilterStrategy;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.IOUtils;

View File

@ -18,6 +18,7 @@
package org.apache.lucene.search;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.LeafReaderContext;
@ -106,6 +107,19 @@ public class TestFilteredSearch extends LuceneTestCase {
public String toString(String field) {
return "SimpleDocIdSetFilter";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return Arrays.equals(docs, ((SimpleDocIdSetFilter) obj).docs);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + Arrays.hashCode(docs);
}
}
}

View File

@ -55,6 +55,18 @@ public class TestQueryWrapperFilter extends LuceneTestCase {
return in.toString(field);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return in.equals(((FilterWrapper) obj).in);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + in.hashCode();
}
}
public void testBasic() throws Exception {
@ -211,4 +223,8 @@ public class TestQueryWrapperFilter extends LuceneTestCase {
reader.close();
dir.close();
}
public void testBasics() {
QueryUtils.check(new QueryWrapperFilter(new TermQuery(new Term("foo", "bar"))));
}
}

View File

@ -140,20 +140,41 @@ public class TestScorerPerf extends LuceneTestCase {
}
}
private static class BitSetFilter extends Filter {
private final FixedBitSet docs;
BitSetFilter(FixedBitSet docs) {
this.docs = docs;
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs) throws IOException {
assertNull("acceptDocs should be null, as we have an index without deletions", acceptDocs);
return new BitDocIdSet(docs);
}
@Override
public String toString(String field) {
return "randomBitSetFilter";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return docs == ((BitSetFilter) obj).docs;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + System.identityHashCode(docs);
}
}
FixedBitSet addClause(BooleanQuery bq, FixedBitSet result) {
final FixedBitSet rnd = sets[random().nextInt(sets.length)];
Query q = new ConstantScoreQuery(new Filter() {
@Override
public DocIdSet getDocIdSet (LeafReaderContext context, Bits acceptDocs) {
assertNull("acceptDocs should be null, as we have an index without deletions", acceptDocs);
return new BitDocIdSet(rnd);
}
@Override
public String toString(String field) {
return "randomBitSetFilter";
}
});
Query q = new ConstantScoreQuery(new BitSetFilter(rnd));
bq.add(q, BooleanClause.Occur.MUST);
if (validate) {
if (result==null) result = rnd.clone();

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
@ -30,16 +31,16 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
@ -147,7 +148,7 @@ public class TestSortRandom extends LuceneTestCase {
sort = new Sort(sf, SortField.FIELD_DOC);
}
final int hitCount = TestUtil.nextInt(random, 1, r.maxDoc() + 20);
final RandomFilter f = new RandomFilter(random, random.nextFloat(), docValues);
final RandomFilter f = new RandomFilter(random.nextLong(), random.nextFloat(), docValues);
int queryType = random.nextInt(2);
if (queryType == 0) {
// force out of order
@ -232,20 +233,21 @@ public class TestSortRandom extends LuceneTestCase {
}
private static class RandomFilter extends Filter {
private final Random random;
private final long seed;
private float density;
private final List<BytesRef> docValues;
public final List<BytesRef> matchValues = Collections.synchronizedList(new ArrayList<BytesRef>());
// density should be 0.0 ... 1.0
public RandomFilter(Random random, float density, List<BytesRef> docValues) {
this.random = random;
public RandomFilter(long seed, float density, List<BytesRef> docValues) {
this.seed = seed;
this.density = density;
this.docValues = docValues;
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs) throws IOException {
Random random = new Random(context.docBase ^ seed);
final int maxDoc = context.reader().maxDoc();
final NumericDocValues idSource = DocValues.getNumeric(context.reader(), "id");
assertNotNull(idSource);
@ -265,5 +267,22 @@ public class TestSortRandom extends LuceneTestCase {
public String toString(String field) {
return "RandomFilter(density=" + density + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
RandomFilter other = (RandomFilter) obj;
return seed == other.seed && docValues == other.docValues;
}
@Override
public int hashCode() {
int h = Objects.hash(seed, density);
h = 31 * h + System.identityHashCode(docValues);
h = 31 * h + super.hashCode();
return h;
}
}
}

View File

@ -19,6 +19,7 @@ package org.apache.lucene.facet.range;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
@ -101,58 +102,85 @@ public final class DoubleRange extends Range {
return "DoubleRange(" + minIncl + " to " + maxIncl + ")";
}
@Override
public Filter getFilter(final Filter fastMatchFilter, final ValueSource valueSource) {
return new Filter() {
private static class ValueSourceFilter extends Filter {
private final DoubleRange range;
private final Filter fastMatchFilter;
private final ValueSource valueSource;
@Override
public String toString(String field) {
return "Filter(" + DoubleRange.this.toString() + ")";
ValueSourceFilter(DoubleRange range, Filter fastMatchFilter, ValueSource valueSource) {
this.range = range;
this.fastMatchFilter = fastMatchFilter;
this.valueSource = valueSource;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
ValueSourceFilter other = (ValueSourceFilter) obj;
return range.equals(other.range)
&& Objects.equals(fastMatchFilter, other.fastMatchFilter)
&& valueSource.equals(other.valueSource);
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, final Bits acceptDocs) throws IOException {
@Override
public int hashCode() {
return 31 * Objects.hash(range, fastMatchFilter, valueSource) + super.hashCode();
}
// TODO: this is just like ValueSourceScorer,
// ValueSourceFilter (spatial),
// ValueSourceRangeFilter (solr); also,
// https://issues.apache.org/jira/browse/LUCENE-4251
@Override
public String toString(String field) {
return "Filter(" + range.toString() + ")";
}
final FunctionValues values = valueSource.getValues(Collections.emptyMap(), context);
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, final Bits acceptDocs) throws IOException {
final int maxDoc = context.reader().maxDoc();
// TODO: this is just like ValueSourceScorer,
// ValueSourceFilter (spatial),
// ValueSourceRangeFilter (solr); also,
// https://issues.apache.org/jira/browse/LUCENE-4251
final DocIdSet fastMatchDocs;
if (fastMatchFilter != null) {
fastMatchDocs = fastMatchFilter.getDocIdSet(context, null);
if (fastMatchDocs == null) {
// No documents match
return null;
}
} else {
fastMatchDocs = new DocIdSet() {
@Override
public long ramBytesUsed() {
return 0;
}
@Override
public DocIdSetIterator iterator() throws IOException {
return DocIdSetIterator.all(maxDoc);
}
};
final FunctionValues values = valueSource.getValues(Collections.emptyMap(), context);
final int maxDoc = context.reader().maxDoc();
final DocIdSet fastMatchDocs;
if (fastMatchFilter != null) {
fastMatchDocs = fastMatchFilter.getDocIdSet(context, null);
if (fastMatchDocs == null) {
// No documents match
return null;
}
return new FilteredDocIdSet(fastMatchDocs) {
} else {
fastMatchDocs = new DocIdSet() {
@Override
protected boolean match(int docID) {
if (acceptDocs != null && acceptDocs.get(docID) == false) {
return false;
}
return accept(values.doubleVal(docID));
public long ramBytesUsed() {
return 0;
}
@Override
public DocIdSetIterator iterator() throws IOException {
return DocIdSetIterator.all(maxDoc);
}
};
}
};
return new FilteredDocIdSet(fastMatchDocs) {
@Override
protected boolean match(int docID) {
if (acceptDocs != null && acceptDocs.get(docID) == false) {
return false;
}
return range.accept(values.doubleVal(docID));
}
};
}
}
@Override
public Filter getFilter(final Filter fastMatchFilter, final ValueSource valueSource) {
return new ValueSourceFilter(this, fastMatchFilter, valueSource);
}
}

View File

@ -19,6 +19,7 @@ package org.apache.lucene.facet.range;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
@ -93,57 +94,84 @@ public final class LongRange extends Range {
return "LongRange(" + minIncl + " to " + maxIncl + ")";
}
@Override
public Filter getFilter(final Filter fastMatchFilter, final ValueSource valueSource) {
return new Filter() {
private static class ValueSourceFilter extends Filter {
private final LongRange range;
private final Filter fastMatchFilter;
private final ValueSource valueSource;
@Override
public String toString(String field) {
return "Filter(" + LongRange.this.toString() + ")";
ValueSourceFilter(LongRange range, Filter fastMatchFilter, ValueSource valueSource) {
this.range = range;
this.fastMatchFilter = fastMatchFilter;
this.valueSource = valueSource;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
ValueSourceFilter other = (ValueSourceFilter) obj;
return range.equals(other.range)
&& Objects.equals(fastMatchFilter, other.fastMatchFilter)
&& valueSource.equals(other.valueSource);
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, final Bits acceptDocs) throws IOException {
@Override
public int hashCode() {
return 31 * Objects.hash(range, fastMatchFilter, valueSource) + super.hashCode();
}
// TODO: this is just like ValueSourceScorer,
// ValueSourceFilter (spatial),
// ValueSourceRangeFilter (solr); also,
// https://issues.apache.org/jira/browse/LUCENE-4251
@Override
public String toString(String field) {
return "Filter(" + range.toString() + ")";
}
final FunctionValues values = valueSource.getValues(Collections.emptyMap(), context);
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, final Bits acceptDocs) throws IOException {
final int maxDoc = context.reader().maxDoc();
// TODO: this is just like ValueSourceScorer,
// ValueSourceFilter (spatial),
// ValueSourceRangeFilter (solr); also,
// https://issues.apache.org/jira/browse/LUCENE-4251
final DocIdSet fastMatchDocs;
if (fastMatchFilter != null) {
fastMatchDocs = fastMatchFilter.getDocIdSet(context, null);
if (fastMatchDocs == null) {
// No documents match
return null;
}
} else {
fastMatchDocs = new DocIdSet() {
@Override
public long ramBytesUsed() {
return 0;
}
@Override
public DocIdSetIterator iterator() throws IOException {
return DocIdSetIterator.all(maxDoc);
}
};
final FunctionValues values = valueSource.getValues(Collections.emptyMap(), context);
final int maxDoc = context.reader().maxDoc();
final DocIdSet fastMatchDocs;
if (fastMatchFilter != null) {
fastMatchDocs = fastMatchFilter.getDocIdSet(context, null);
if (fastMatchDocs == null) {
// No documents match
return null;
}
return new FilteredDocIdSet(fastMatchDocs) {
} else {
fastMatchDocs = new DocIdSet() {
@Override
protected boolean match(int docID) {
if (acceptDocs != null && acceptDocs.get(docID) == false) {
return false;
}
return accept(values.longVal(docID));
public long ramBytesUsed() {
return 0;
}
@Override
public DocIdSetIterator iterator() throws IOException {
return DocIdSetIterator.all(maxDoc);
}
};
}
};
return new FilteredDocIdSet(fastMatchDocs) {
@Override
protected boolean match(int docID) {
if (acceptDocs != null && acceptDocs.get(docID) == false) {
return false;
}
return range.accept(values.longVal(docID));
}
};
}
}
@Override
public Filter getFilter(final Filter fastMatchFilter, final ValueSource valueSource) {
return new ValueSourceFilter(this, fastMatchFilter, valueSource);
}
}

View File

@ -46,7 +46,6 @@ import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.queries.function.FunctionValues;
@ -55,19 +54,14 @@ import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
import org.apache.lucene.queries.function.valuesource.LongFieldSource;
import org.apache.lucene.search.CachingWrapperQuery;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.QueryCachingPolicy;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.TestUtil;
@ -849,6 +843,42 @@ public class TestRangeFacetCounts extends FacetTestCase {
IOUtils.close(r, d);
}
private static class UsedFilter extends Filter {
private final AtomicBoolean used;
private final Filter in;
UsedFilter(Filter in, AtomicBoolean used) {
this.in = in;
this.used = used;
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs)
throws IOException {
used.set(true);
return in.getDocIdSet(context, acceptDocs);
}
@Override
public String toString(String field) {
return in.toString(field);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return in.equals(((UsedFilter) obj).in);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + in.hashCode();
}
}
public void testCustomDoublesValueSource() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
@ -875,12 +905,12 @@ public class TestRangeFacetCounts extends FacetTestCase {
@Override
public boolean equals(Object o) {
throw new UnsupportedOperationException();
return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
throw new UnsupportedOperationException();
return getClass().hashCode();
}
@Override
@ -910,18 +940,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
if (random().nextBoolean()) {
// Sort of silly:
final Filter in = new QueryWrapperFilter(new MatchAllDocsQuery());
fastMatchFilter = new Filter() {
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs)
throws IOException {
filterWasUsed.set(true);
return in.getDocIdSet(context, acceptDocs);
}
@Override
public String toString(String field) {
return in.toString(field);
}
};
fastMatchFilter = new UsedFilter(in, filterWasUsed);
} else {
fastMatchFilter = null;
}

View File

@ -87,13 +87,15 @@ public class BitDocIdSetCachingWrapperFilter extends BitDocIdSetFilter {
@Override
public boolean equals(Object o) {
if (o == null || !getClass().equals(o.getClass())) return false;
if (super.equals(o) == false) {
return false;
}
final BitDocIdSetCachingWrapperFilter other = (BitDocIdSetCachingWrapperFilter) o;
return this.filter.equals(other.filter);
}
@Override
public int hashCode() {
return (filter.hashCode() ^ getClass().hashCode());
return 31 * super.hashCode() + filter.hashCode();
}
}

View File

@ -87,6 +87,19 @@ public class TestBlockJoinSorter extends LuceneTestCase {
return docIdSet == EMPTY ? null : BitsFilteredDocIdSet.wrap(docIdSet, acceptDocs);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return filter.equals(((BitSetCachingWrapperFilter) obj).filter);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + filter.hashCode();
}
@Override
public String toString(String field) {
return getClass().getName() + "(" + filter.toString(field) + ")";

View File

@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
@ -32,9 +33,9 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.search.BooleanClause.Occur;
@ -51,9 +52,9 @@ import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopFieldDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.uninverting.UninvertingReader.Type;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
@ -163,7 +164,7 @@ public class TestFieldCacheSortRandom extends LuceneTestCase {
sort = new Sort(sf, SortField.FIELD_DOC);
}
final int hitCount = TestUtil.nextInt(random, 1, r.maxDoc() + 20);
final RandomFilter f = new RandomFilter(random, random.nextFloat(), docValues);
final RandomFilter f = new RandomFilter(random.nextLong(), random.nextFloat(), docValues);
int queryType = random.nextInt(3);
if (queryType == 0) {
// force out of order
@ -266,20 +267,21 @@ public class TestFieldCacheSortRandom extends LuceneTestCase {
}
private static class RandomFilter extends Filter {
private final Random random;
private final long seed;
private float density;
private final List<BytesRef> docValues;
public final List<BytesRef> matchValues = Collections.synchronizedList(new ArrayList<BytesRef>());
// density should be 0.0 ... 1.0
public RandomFilter(Random random, float density, List<BytesRef> docValues) {
this.random = random;
public RandomFilter(long seed, float density, List<BytesRef> docValues) {
this.seed = seed;
this.density = density;
this.docValues = docValues;
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs) throws IOException {
Random random = new Random(seed ^ context.docBase);
final int maxDoc = context.reader().maxDoc();
final NumericDocValues idSource = DocValues.getNumeric(context.reader(), "id");
assertNotNull(idSource);
@ -299,5 +301,22 @@ public class TestFieldCacheSortRandom extends LuceneTestCase {
public String toString(String field) {
return "RandomFilter(density=" + density + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
RandomFilter other = (RandomFilter) obj;
return seed == other.seed && docValues == other.docValues;
}
@Override
public int hashCode() {
int h = Objects.hash(seed, density);
h = 31 * h + System.identityHashCode(docValues);
h = 31 * h + super.hashCode();
return h;
}
}
}

View File

@ -195,7 +195,7 @@ public class DuplicateFilter extends Filter {
if (this == obj) {
return true;
}
if ((obj == null) || (obj.getClass() != this.getClass())) {
if (super.equals(obj) == false) {
return false;
}
@ -216,7 +216,7 @@ public class DuplicateFilter extends Filter {
@Override
public int hashCode() {
int hash = 217;
int hash = super.hashCode();
hash = 31 * hash + keepMode.hashCode();
hash = 31 * hash + processingMode.hashCode();
hash = 31 * hash + fieldName.hashCode();

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
@ -38,15 +39,15 @@ import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
@ -651,6 +652,20 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
public String toString(String field) {
return "RandomFilter(seed=" + seed + ",density=" + density + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
RandomFilter other = (RandomFilter) obj;
return seed == other.seed && density == other.density;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), seed, density);
}
}
/** See if we can create a TAQ with cycles */

View File

@ -66,7 +66,6 @@ public class IntersectsRPTVerifyQuery extends Query {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof IntersectsRPTVerifyQuery)) return false;
if (!super.equals(o)) return false;
IntersectsRPTVerifyQuery that = (IntersectsRPTVerifyQuery) o;

View File

@ -52,7 +52,7 @@ public abstract class AbstractPrefixTreeFilter extends Filter {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!getClass().equals(o.getClass())) return false;
if (super.equals(o) == false) return false;
AbstractPrefixTreeFilter that = (AbstractPrefixTreeFilter) o;
@ -65,7 +65,8 @@ public abstract class AbstractPrefixTreeFilter extends Filter {
@Override
public int hashCode() {
int result = queryShape.hashCode();
int result = super.hashCode();
result = 31 * result + queryShape.hashCode();
result = 31 * result + fieldName.hashCode();
result = 31 * result + detailLevel;
return result;

View File

@ -62,19 +62,6 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
assert detailLevel <= grid.getMaxLevels();
}
@Override
public boolean equals(Object o) {
return super.equals(o);//checks getClass == o.getClass & instanceof
//Ignore hasIndexedLeaves as it's fixed for a specific field, which super.equals compares
//Ignore prefixGridScanLevel as it is merely a tuning parameter.
}
@Override
public int hashCode() {
return super.hashCode();
}
/**
* An abstract class designed to make it easy to implement predicates or
* other operations on a {@link SpatialPrefixTree} indexed field. An instance

View File

@ -183,7 +183,7 @@ public class SerializedDVStrategy extends SpatialStrategy {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (super.equals(o) == false) return false;
PredicateValueSourceFilter that = (PredicateValueSourceFilter) o;
@ -194,7 +194,7 @@ public class SerializedDVStrategy extends SpatialStrategy {
@Override
public int hashCode() {
return predicateValueSource.hashCode();
return super.hashCode() + 31 * predicateValueSource.hashCode();
}
@Override

View File

@ -26,6 +26,7 @@ import org.apache.lucene.search.FilteredDocIdSet;
import org.apache.lucene.util.Bits;
import java.io.IOException;
import java.util.Objects;
/**
* Filter that matches all documents where a ValueSource is
@ -72,4 +73,20 @@ public class ValueSourceFilter extends Filter {
"max=" + max +
")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
ValueSourceFilter other = (ValueSourceFilter) obj;
return startingFilter.equals(other.startingFilter)
&& source.equals(other.source)
&& min == min && max == max;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), startingFilter, source, min, max);
}
}

View File

@ -54,6 +54,7 @@ import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BitDocIdSet;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.FixedBitSet;
@ -700,42 +701,46 @@ public class SuggestFieldTest extends LuceneTestCase {
iw.close();
}
private static class RandomAccessFilter extends Filter {
private final Filter in;
private RandomAccessFilter(Filter in) {
this.in = in;
}
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs) throws IOException {
DocIdSet docIdSet = in.getDocIdSet(context, acceptDocs);
DocIdSetIterator iterator = docIdSet.iterator();
FixedBitSet bits = new FixedBitSet(context.reader().maxDoc());
if (iterator != null) {
bits.or(iterator);
}
return new BitDocIdSet(bits);
}
@Override
public String toString(String field) {
return in.toString(field);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return in.equals(((RandomAccessFilter) obj).in);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + in.hashCode();
}
}
private static Filter randomAccessFilter(Filter filter) {
return new Filter() {
@Override
public DocIdSet getDocIdSet(LeafReaderContext context, Bits acceptDocs) throws IOException {
DocIdSet docIdSet = filter.getDocIdSet(context, acceptDocs);
DocIdSetIterator iterator = docIdSet.iterator();
FixedBitSet bits = new FixedBitSet(context.reader().maxDoc());
if (iterator != null) {
int doc;
while((doc = iterator.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
bits.set(doc);
}
}
return new DocIdSet() {
@Override
public DocIdSetIterator iterator() throws IOException {
return iterator;
}
@Override
public Bits bits() throws IOException {
return bits;
}
@Override
public long ramBytesUsed() {
return docIdSet.ramBytesUsed();
}
};
}
@Override
public String toString(String field) {
return filter.toString(field);
}
};
return new RandomAccessFilter(filter);
}
private static class Entry {

View File

@ -50,6 +50,15 @@ public class QueryUtils {
/** Check the types of things query objects should be able to do. */
public static void check(Query q) {
checkHashEquals(q);
if (q instanceof FilteredQuery) {
// This is our best option to have coverage on filters since they are
// rarely searched on directly
// This hack can go away when FilteredQuery goes away too
FilteredQuery filtered = (FilteredQuery) q;
check(filtered.getQuery());
check(filtered.getFilter());
}
}
/** check very basic hashCode and equals */

View File

@ -226,6 +226,20 @@ public abstract class SearchEquivalenceTestBase extends LuceneTestCase {
public String toString(String field) {
return "SlowQWF(" + query + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
return query.equals(((SlowWrapperFilter) obj).query);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + query.hashCode();
}
}
/**