Make ContextIndexSearcher delegate more method calls to Engine.searcher().

When running tests, Engine.searcher() is going to be an AssertingIndexSearcher
so we definitely don't want to discard it. This commit fixes it as well as the
bugs it found.

Closes #3987
This commit is contained in:
Adrien Grand 2013-10-25 19:00:17 +02:00
parent ce891e93b6
commit 2e8bbe9e30
27 changed files with 404 additions and 61 deletions

View File

@ -0,0 +1,250 @@
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 org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.Version;
import org.elasticsearch.common.lucene.Lucene;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
/**
* Extension of {@link ConstantScoreQuery} that works around LUCENE-5307.
*/
// we extend CSQ so that highlighters know how to deal with this query
public class XLuceneConstantScoreQuery extends ConstantScoreQuery {
static {
assert Version.LUCENE_45.onOrAfter(Lucene.VERSION) : "Lucene 4.6 CSQ is fixed, remove this one!";
}
public XLuceneConstantScoreQuery(Query filter) {
super(filter);
}
public XLuceneConstantScoreQuery(Filter filter) {
super(filter);
}
@Override
public Query rewrite(IndexReader reader) throws IOException {
if (query != null) {
Query rewritten = query.rewrite(reader);
if (rewritten != query) {
rewritten = new XLuceneConstantScoreQuery(rewritten);
rewritten.setBoost(this.getBoost());
return rewritten;
}
} else {
assert filter != null;
// Fix outdated usage pattern from Lucene 2.x/early-3.x:
// because ConstantScoreQuery only accepted filters,
// QueryWrapperFilter was used to wrap queries.
if (filter instanceof QueryWrapperFilter) {
final QueryWrapperFilter qwf = (QueryWrapperFilter) filter;
final Query rewritten = new XLuceneConstantScoreQuery(qwf.getQuery().rewrite(reader));
rewritten.setBoost(this.getBoost());
return rewritten;
}
}
return this;
}
@Override
public Weight createWeight(IndexSearcher searcher) throws IOException {
return new XConstantWeight(searcher);
}
protected class XConstantWeight extends Weight {
private final Weight innerWeight;
private float queryNorm;
private float queryWeight;
public XConstantWeight(IndexSearcher searcher) throws IOException {
this.innerWeight = (query == null) ? null : query.createWeight(searcher);
}
@Override
public Query getQuery() {
return XLuceneConstantScoreQuery.this;
}
@Override
public float getValueForNormalization() throws IOException {
// we calculate sumOfSquaredWeights of the inner weight, but ignore it (just to initialize everything)
if (innerWeight != null) innerWeight.getValueForNormalization();
queryWeight = getBoost();
return queryWeight * queryWeight;
}
@Override
public void normalize(float norm, float topLevelBoost) {
this.queryNorm = norm * topLevelBoost;
queryWeight *= this.queryNorm;
// we normalize the inner weight, but ignore it (just to initialize everything)
if (innerWeight != null) innerWeight.normalize(norm, topLevelBoost);
}
@Override
public Scorer scorer(AtomicReaderContext context, boolean scoreDocsInOrder,
boolean topScorer, final Bits acceptDocs) throws IOException {
final DocIdSetIterator disi;
if (filter != null) {
assert query == null;
final DocIdSet dis = filter.getDocIdSet(context, acceptDocs);
if (dis == null) {
return null;
}
disi = dis.iterator();
} else {
assert query != null && innerWeight != null;
disi = innerWeight.scorer(context, scoreDocsInOrder, topScorer, acceptDocs);
}
if (disi == null) {
return null;
}
return new XConstantScorer(disi, this, queryWeight);
}
@Override
public boolean scoresDocsOutOfOrder() {
return (innerWeight != null) ? innerWeight.scoresDocsOutOfOrder() : false;
}
@Override
public Explanation explain(AtomicReaderContext context, int doc) throws IOException {
final Scorer cs = scorer(context, true, false, context.reader().getLiveDocs());
final boolean exists = (cs != null && cs.advance(doc) == doc);
final ComplexExplanation result = new ComplexExplanation();
if (exists) {
result.setDescription(XLuceneConstantScoreQuery.this.toString() + ", product of:");
result.setValue(queryWeight);
result.setMatch(Boolean.TRUE);
result.addDetail(new Explanation(getBoost(), "boost"));
result.addDetail(new Explanation(queryNorm, "queryNorm"));
} else {
result.setDescription(XLuceneConstantScoreQuery.this.toString() + " doesn't match id " + doc);
result.setValue(0);
result.setMatch(Boolean.FALSE);
}
return result;
}
}
protected class XConstantScorer extends Scorer {
final DocIdSetIterator docIdSetIterator;
final float theScore;
public XConstantScorer(DocIdSetIterator docIdSetIterator, Weight w, float theScore) {
super(w);
this.theScore = theScore;
this.docIdSetIterator = docIdSetIterator;
}
@Override
public int nextDoc() throws IOException {
return docIdSetIterator.nextDoc();
}
@Override
public int docID() {
return docIdSetIterator.docID();
}
@Override
public float score() throws IOException {
assert docIdSetIterator.docID() != NO_MORE_DOCS;
return theScore;
}
@Override
public int freq() throws IOException {
return 1;
}
@Override
public int advance(int target) throws IOException {
return docIdSetIterator.advance(target);
}
@Override
public long cost() {
return docIdSetIterator.cost();
}
private Collector wrapCollector(final Collector collector) {
return new Collector() {
@Override
public void setScorer(Scorer scorer) throws IOException {
// we must wrap again here, but using the scorer passed in as parameter:
collector.setScorer(new ConstantScorer(scorer, XConstantScorer.this.weight, XConstantScorer.this.theScore));
}
@Override
public void collect(int doc) throws IOException {
collector.collect(doc);
}
@Override
public void setNextReader(AtomicReaderContext context) throws IOException {
collector.setNextReader(context);
}
@Override
public boolean acceptsDocsOutOfOrder() {
return collector.acceptsDocsOutOfOrder();
}
};
}
// this optimization allows out of order scoring as top scorer!
@Override
public void score(Collector collector) throws IOException {
if (query != null) {
((Scorer) docIdSetIterator).score(wrapCollector(collector));
} else {
super.score(collector);
}
}
// this optimization allows out of order scoring as top scorer,
@Override
public boolean score(Collector collector, int max, int firstDocID) throws IOException {
if (query != null) {
return ((Scorer) docIdSetIterator).score(wrapCollector(collector), max, firstDocID);
} else {
return super.score(collector, max, firstDocID);
}
}
@Override
public Collection<ChildScorer> getChildren() {
if (query != null)
return Collections.singletonList(new ChildScorer((Scorer) docIdSetIterator, "constant"));
else
return Collections.emptyList();
}
}
}

View File

@ -116,7 +116,7 @@ public class Lucene {
TotalHitCountCollector countCollector = new TotalHitCountCollector(); TotalHitCountCollector countCollector = new TotalHitCountCollector();
// we don't need scores, so wrap it in a constant score query // we don't need scores, so wrap it in a constant score query
if (!(query instanceof ConstantScoreQuery)) { if (!(query instanceof ConstantScoreQuery)) {
query = new ConstantScoreQuery(query); query = new XLuceneConstantScoreQuery(query);
} }
searcher.search(query, countCollector); searcher.search(query, countCollector);
return countCollector.getTotalHits(); return countCollector.getTotalHits();

View File

@ -29,33 +29,36 @@ import java.io.IOException;
*/ */
public class EmptyScorer extends Scorer { public class EmptyScorer extends Scorer {
private int docId = -1;
public EmptyScorer(Weight weight) { public EmptyScorer(Weight weight) {
super(weight); super(weight);
} }
@Override @Override
public float score() throws IOException { public float score() throws IOException {
return 0; throw new UnsupportedOperationException("Should never be called");
} }
@Override @Override
public int freq() throws IOException { public int freq() throws IOException {
return 0; throw new UnsupportedOperationException("Should never be called");
} }
@Override @Override
public int docID() { public int docID() {
return -1; return docId;
} }
@Override @Override
public int nextDoc() throws IOException { public int nextDoc() throws IOException {
return NO_MORE_DOCS; assert docId != NO_MORE_DOCS;
return docId = NO_MORE_DOCS;
} }
@Override @Override
public int advance(int target) throws IOException { public int advance(int target) throws IOException {
return NO_MORE_DOCS; return slowAdvance(target);
} }
@Override @Override

View File

@ -32,14 +32,6 @@ import java.util.Set;
*/ */
public final class MatchNoDocsQuery extends Query { public final class MatchNoDocsQuery extends Query {
public static MatchNoDocsQuery INSTANCE = new MatchNoDocsQuery();
/**
* Since all instances of this class are equal to each other,
* we have a constant hash code.
*/
private static final int HASH_CODE = 12345;
/** /**
* Weight implementation that matches no documents. * Weight implementation that matches no documents.
*/ */
@ -92,11 +84,14 @@ public final class MatchNoDocsQuery extends Query {
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
return o instanceof MatchAllDocsQuery; if (o instanceof MatchNoDocsQuery) {
return getBoost() == ((MatchNoDocsQuery) o).getBoost();
}
return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return HASH_CODE; return getClass().hashCode() ^ Float.floatToIntBits(getBoost());
} }
} }

View File

@ -31,6 +31,7 @@ import org.apache.lucene.search.similarities.TFIDFSimilarity;
import org.elasticsearch.common.io.FastStringReader; import org.elasticsearch.common.io.FastStringReader;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Set; import java.util.Set;
/** /**
@ -67,6 +68,68 @@ public class MoreLikeThisQuery extends Query {
this.analyzer = analyzer; this.analyzer = analyzer;
} }
@Override
public int hashCode() {
int result = boostTerms ? 1 : 0;
result = 31 * result + Float.floatToIntBits(boostTermsFactor);
result = 31 * result + likeText.hashCode();
result = 31 * result + maxDocFreq;
result = 31 * result + maxQueryTerms;
result = 31 * result + maxWordLen;
result = 31 * result + minDocFreq;
result = 31 * result + minTermFrequency;
result = 31 * result + minWordLen;
result = 31 * result + Arrays.hashCode(moreLikeFields);
result = 31 * result + Float.floatToIntBits(percentTermsToMatch);
result = 31 * result + (stopWords == null ? 0 : stopWords.hashCode());
result = 31 * result + Float.floatToIntBits(getBoost());
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass())
return false;
MoreLikeThisQuery other = (MoreLikeThisQuery) obj;
if (getBoost() != other.getBoost())
return false;
if (!analyzer.equals(other.analyzer))
return false;
if (boostTerms != other.boostTerms)
return false;
if (boostTermsFactor != other.boostTermsFactor)
return false;
if (!likeText.equals(other.likeText))
return false;
if (maxDocFreq != other.maxDocFreq)
return false;
if (maxQueryTerms != other.maxQueryTerms)
return false;
if (maxWordLen != other.maxWordLen)
return false;
if (minDocFreq != other.minDocFreq)
return false;
if (minTermFrequency != other.minTermFrequency)
return false;
if (minWordLen != other.minWordLen)
return false;
if (!Arrays.equals(moreLikeFields, other.moreLikeFields))
return false;
if (percentTermsToMatch != other.percentTermsToMatch)
return false;
if (similarity == null) {
if (other.similarity != null)
return false;
} else if (!similarity.equals(other.similarity))
return false;
if (stopWords == null) {
if (other.stopWords != null)
return false;
} else if (!stopWords.equals(other.stopWords))
return false;
return true;
}
@Override @Override
public Query rewrite(IndexReader reader) throws IOException { public Query rewrite(IndexReader reader) throws IOException {
MoreLikeThis mlt = new MoreLikeThis(reader, similarity == null ? new DefaultSimilarity() : similarity); MoreLikeThis mlt = new MoreLikeThis(reader, similarity == null ? new DefaultSimilarity() : similarity);
@ -212,4 +275,3 @@ public class MoreLikeThisQuery extends Query {
this.boostTermsFactor = boostTermsFactor; this.boostTermsFactor = boostTermsFactor;
} }
} }

View File

@ -128,7 +128,7 @@ public class MultiPhrasePrefixQuery extends Query {
@Override @Override
public Query rewrite(IndexReader reader) throws IOException { public Query rewrite(IndexReader reader) throws IOException {
if (termArrays.isEmpty()) { if (termArrays.isEmpty()) {
return MatchNoDocsQuery.INSTANCE; return new MatchNoDocsQuery();
} }
MultiPhraseQuery query = new MultiPhraseQuery(); MultiPhraseQuery query = new MultiPhraseQuery();
query.setSlop(slop); query.setSlop(slop);
@ -146,7 +146,7 @@ public class MultiPhrasePrefixQuery extends Query {
} }
} }
if (terms.isEmpty()) { if (terms.isEmpty()) {
return MatchNoDocsQuery.INSTANCE; return Queries.newMatchNoDocsQuery();
} }
query.add(terms.toArray(Term.class), position); query.add(terms.toArray(Term.class), position);
return query.rewrite(reader); return query.rewrite(reader);

View File

@ -33,10 +33,6 @@ import java.util.regex.Pattern;
*/ */
public class Queries { public class Queries {
/* In general we should never us a static query instance and share it.
* In this case the instance is immutable so that's ok.*/
public final static Query NO_MATCH_QUERY = MatchNoDocsQuery.INSTANCE;
/** /**
* A match all docs filter. Note, requires no caching!. * A match all docs filter. Note, requires no caching!.
*/ */
@ -50,6 +46,11 @@ public class Queries {
return new XConstantScoreQuery(MATCH_ALL_FILTER); return new XConstantScoreQuery(MATCH_ALL_FILTER);
} }
/** Return a query that matches no document. */
public static Query newMatchNoDocsQuery() {
return new MatchNoDocsQuery();
}
/** /**
* Optimizes the given query and returns the optimized version of it. * Optimizes the given query and returns the optimized version of it.
*/ */

View File

@ -19,13 +19,13 @@
package org.elasticsearch.common.lucene.search; package org.elasticsearch.common.lucene.search;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter; import org.apache.lucene.search.Filter;
import org.apache.lucene.search.XLuceneConstantScoreQuery;
/** /**
* We still need sometimes to exclude deletes, because we don't remove them always with acceptDocs on filters * We still need sometimes to exclude deletes, because we don't remove them always with acceptDocs on filters
*/ */
public class XConstantScoreQuery extends ConstantScoreQuery { public class XConstantScoreQuery extends XLuceneConstantScoreQuery {
private final Filter actualFilter; private final Filter actualFilter;

View File

@ -41,7 +41,7 @@ import java.util.Set;
*/ */
// Changes are marked with //CHANGE: // Changes are marked with //CHANGE:
// Delegate to FilteredQuery - this version fixes the bug in LUCENE-4705 and uses ApplyAcceptedDocsFilter internally // Delegate to FilteredQuery - this version fixes the bug in LUCENE-4705 and uses ApplyAcceptedDocsFilter internally
public class XFilteredQuery extends Query { public final class XFilteredQuery extends Query {
private final Filter rawFilter; private final Filter rawFilter;
private final FilteredQuery delegate; private final FilteredQuery delegate;
private final FilterStrategy strategy; private final FilterStrategy strategy;
@ -67,7 +67,11 @@ public class XFilteredQuery extends Query {
* @see FilterStrategy * @see FilterStrategy
*/ */
public XFilteredQuery(Query query, Filter filter, FilterStrategy strategy) { public XFilteredQuery(Query query, Filter filter, FilterStrategy strategy) {
delegate = new FilteredQuery(query, new ApplyAcceptedDocsFilter(filter), strategy); this(new FilteredQuery(query, new ApplyAcceptedDocsFilter(filter), strategy), filter, strategy);
}
private XFilteredQuery(FilteredQuery delegate, Filter filter, FilterStrategy strategy) {
this.delegate = delegate;
// CHANGE: we need to wrap it in post application of accepted docs // CHANGE: we need to wrap it in post application of accepted docs
this.rawFilter = filter; this.rawFilter = filter;
this.strategy = strategy; this.strategy = strategy;
@ -96,7 +100,7 @@ public class XFilteredQuery extends Query {
if (queryRewritten instanceof MatchAllDocsQuery || Queries.isConstantMatchAllQuery(queryRewritten)) { if (queryRewritten instanceof MatchAllDocsQuery || Queries.isConstantMatchAllQuery(queryRewritten)) {
// Special case: If the query is a MatchAllDocsQuery, we only // Special case: If the query is a MatchAllDocsQuery, we only
// return a CSQ(filter). // return a CSQ(filter).
final Query rewritten = new ConstantScoreQuery(delegate.getFilter()); final Query rewritten = new XLuceneConstantScoreQuery(delegate.getFilter());
// Combine boost of MatchAllDocsQuery and the wrapped rewritten query: // Combine boost of MatchAllDocsQuery and the wrapped rewritten query:
rewritten.setBoost(delegate.getBoost() * queryRewritten.getBoost()); rewritten.setBoost(delegate.getBoost() * queryRewritten.getBoost());
return rewritten; return rewritten;
@ -249,4 +253,9 @@ public class XFilteredQuery extends Query {
} }
} }
@Override
public Query clone() {
return new XFilteredQuery((FilteredQuery) delegate.clone(), rawFilter, strategy);
}
} }

View File

@ -358,7 +358,7 @@ public class FiltersFunctionScoreQuery extends Query {
} }
public boolean equals(Object o) { public boolean equals(Object o) {
if (getClass() != o.getClass()) if (o == null || getClass() != o.getClass())
return false; return false;
FiltersFunctionScoreQuery other = (FiltersFunctionScoreQuery) o; FiltersFunctionScoreQuery other = (FiltersFunctionScoreQuery) o;
if (this.getBoost() != other.getBoost()) if (this.getBoost() != other.getBoost())

View File

@ -191,7 +191,7 @@ public class FunctionScoreQuery extends Query {
} }
public boolean equals(Object o) { public boolean equals(Object o) {
if (getClass() != o.getClass()) if (o == null || getClass() != o.getClass())
return false; return false;
FunctionScoreQuery other = (FunctionScoreQuery) o; FunctionScoreQuery other = (FunctionScoreQuery) o;
return this.getBoost() == other.getBoost() && this.subQuery.equals(other.subQuery) && this.function.equals(other.function) return this.getBoost() == other.getBoost() && this.subQuery.equals(other.subQuery) && this.function.equals(other.function)

View File

@ -170,7 +170,7 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
return super.termQuery(value, context); return super.termQuery(value, context);
} }
// no need for constant score filter, since we don't cache the filter, and it always takes deletes into account // no need for constant score filter, since we don't cache the filter, and it always takes deletes into account
return new ConstantScoreQuery(termFilter(value, context)); return new XLuceneConstantScoreQuery(termFilter(value, context));
} }
@Override @Override

View File

@ -25,9 +25,9 @@ import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.queries.TermFilter; import org.apache.lucene.queries.TermFilter;
import org.apache.lucene.queries.TermsFilter; import org.apache.lucene.queries.TermsFilter;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter; import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.XLuceneConstantScoreQuery;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
@ -249,7 +249,7 @@ public class ParentFieldMapper extends AbstractFieldMapper<Uid> implements Inter
if (context == null) { if (context == null) {
return super.termQuery(value, context); return super.termQuery(value, context);
} }
return new ConstantScoreQuery(termFilter(value, context)); return new XLuceneConstantScoreQuery(termFilter(value, context));
} }
@Override @Override

View File

@ -19,9 +19,9 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter; import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.XLuceneConstantScoreQuery;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.XConstantScoreQuery; import org.elasticsearch.common.lucene.search.XConstantScoreQuery;
@ -104,7 +104,7 @@ public class ConstantScoreQueryParser implements QueryParser {
return query1; return query1;
} }
// Query // Query
query = new ConstantScoreQuery(query); query = new XLuceneConstantScoreQuery(query);
query.setBoost(boost); query.setBoost(boost);
return query; return query;
} }

View File

@ -22,8 +22,8 @@ package org.elasticsearch.index.query;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.apache.lucene.queries.TermsFilter; import org.apache.lucene.queries.TermsFilter;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.XLuceneConstantScoreQuery;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.lucene.search.Queries;
@ -106,7 +106,7 @@ public class IdsQueryParser implements QueryParser {
} }
if (ids.isEmpty()) { if (ids.isEmpty()) {
return Queries.NO_MATCH_QUERY; return Queries.newMatchNoDocsQuery();
} }
if (types == null || types.isEmpty()) { if (types == null || types.isEmpty()) {
@ -117,7 +117,7 @@ public class IdsQueryParser implements QueryParser {
TermsFilter filter = new TermsFilter(UidFieldMapper.NAME, Uid.createTypeUids(types, ids)); TermsFilter filter = new TermsFilter(UidFieldMapper.NAME, Uid.createTypeUids(types, ids));
// no need for constant score filter, since we don't cache the filter, and it always takes deletes into account // no need for constant score filter, since we don't cache the filter, and it always takes deletes into account
ConstantScoreQuery query = new ConstantScoreQuery(filter); XLuceneConstantScoreQuery query = new XLuceneConstantScoreQuery(filter);
query.setBoost(boost); query.setBoost(boost);
if (queryName != null) { if (queryName != null) {
parseContext.addNamedQuery(queryName, query); parseContext.addNamedQuery(queryName, query);

View File

@ -283,7 +283,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
parseContext.reset(parser); parseContext.reset(parser);
Query query = parseContext.parseInnerQuery(); Query query = parseContext.parseInnerQuery();
if (query == null) { if (query == null) {
query = Queries.NO_MATCH_QUERY; query = Queries.newMatchNoDocsQuery();
} }
return new ParsedQuery(query, parseContext.copyNamedFilters()); return new ParsedQuery(query, parseContext.copyNamedFilters());
} }

View File

@ -97,7 +97,7 @@ public class IndicesQueryParser implements QueryParser {
if ("all".equals(type)) { if ("all".equals(type)) {
noMatchQuery = Queries.newMatchAllQuery(); noMatchQuery = Queries.newMatchAllQuery();
} else if ("none".equals(type)) { } else if ("none".equals(type)) {
noMatchQuery = MatchNoDocsQuery.INSTANCE; noMatchQuery = Queries.newMatchNoDocsQuery();
} }
} else if ("_name".equals(currentFieldName)) { } else if ("_name".equals(currentFieldName)) {
queryName = parser.text(); queryName = parser.text();

View File

@ -33,7 +33,6 @@ import org.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.ElasticSearchIllegalArgumentException; import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.FieldMapper;
@ -390,6 +389,6 @@ public class MatchQuery {
} }
protected Query zeroTermsQuery() { protected Query zeroTermsQuery() {
return zeroTermsQuery == ZeroTermsQuery.NONE ? MatchNoDocsQuery.INSTANCE : Queries.newMatchAllQuery(); return zeroTermsQuery == ZeroTermsQuery.NONE ? Queries.newMatchNoDocsQuery() : Queries.newMatchAllQuery();
} }
} }

View File

@ -101,7 +101,7 @@ public class ChildrenConstantScoreQuery extends Query {
int remaining = collectedUids.v().size(); int remaining = collectedUids.v().size();
if (remaining == 0) { if (remaining == 0) {
return Queries.NO_MATCH_QUERY.createWeight(searcher); return Queries.newMatchNoDocsQuery().createWeight(searcher);
} }
Filter shortCircuitFilter = null; Filter shortCircuitFilter = null;
@ -261,6 +261,9 @@ public class ChildrenConstantScoreQuery extends Query {
if (shortCircuitParentDocSet != that.shortCircuitParentDocSet) { if (shortCircuitParentDocSet != that.shortCircuitParentDocSet) {
return false; return false;
} }
if (getBoost() != that.getBoost()) {
return false;
}
return true; return true;
} }
@ -268,7 +271,8 @@ public class ChildrenConstantScoreQuery extends Query {
public int hashCode() { public int hashCode() {
int result = originalChildQuery.hashCode(); int result = originalChildQuery.hashCode();
result = 31 * result + childType.hashCode(); result = 31 * result + childType.hashCode();
result += shortCircuitParentDocSet; result = 31 * result + shortCircuitParentDocSet;
result = 31 * result + Float.floatToIntBits(getBoost());
return result; return result;
} }

View File

@ -92,6 +92,9 @@ public class ChildrenQuery extends Query {
if (!childType.equals(that.childType)) { if (!childType.equals(that.childType)) {
return false; return false;
} }
if (getBoost() != that.getBoost()) {
return false;
}
return true; return true;
} }
@ -99,6 +102,7 @@ public class ChildrenQuery extends Query {
public int hashCode() { public int hashCode() {
int result = originalChildQuery.hashCode(); int result = originalChildQuery.hashCode();
result = 31 * result + childType.hashCode(); result = 31 * result + childType.hashCode();
result = 31 * result + Float.floatToIntBits(getBoost());
return result; return result;
} }
@ -158,7 +162,7 @@ public class ChildrenQuery extends Query {
if (uidToCount != null) { if (uidToCount != null) {
uidToCount.release(); uidToCount.release();
} }
return Queries.NO_MATCH_QUERY.createWeight(searcher); return Queries.newMatchNoDocsQuery().createWeight(searcher);
} }
Filter parentFilter; Filter parentFilter;

View File

@ -99,7 +99,7 @@ public class ParentConstantScoreQuery extends Query {
indexSearcher.search(parentQuery, collector); indexSearcher.search(parentQuery, collector);
if (parents.v().isEmpty()) { if (parents.v().isEmpty()) {
return Queries.NO_MATCH_QUERY.createWeight(searcher); return Queries.newMatchNoDocsQuery().createWeight(searcher);
} }
ChildrenWeight childrenWeight = new ChildrenWeight(searchContext, parents); ChildrenWeight childrenWeight = new ChildrenWeight(searchContext, parents);
@ -219,6 +219,7 @@ public class ParentConstantScoreQuery extends Query {
public int hashCode() { public int hashCode() {
int result = originalParentQuery.hashCode(); int result = originalParentQuery.hashCode();
result = 31 * result + parentType.hashCode(); result = 31 * result + parentType.hashCode();
result = 31 * result + Float.floatToIntBits(getBoost());
return result; return result;
} }
@ -238,6 +239,9 @@ public class ParentConstantScoreQuery extends Query {
if (!parentType.equals(that.parentType)) { if (!parentType.equals(that.parentType)) {
return false; return false;
} }
if (this.getBoost() != that.getBoost()) {
return false;
}
return true; return true;
} }

View File

@ -78,6 +78,9 @@ public class ParentQuery extends Query {
if (!parentType.equals(that.parentType)) { if (!parentType.equals(that.parentType)) {
return false; return false;
} }
if (getBoost() != that.getBoost()) {
return false;
}
return true; return true;
} }
@ -85,6 +88,7 @@ public class ParentQuery extends Query {
public int hashCode() { public int hashCode() {
int result = originalParentQuery.hashCode(); int result = originalParentQuery.hashCode();
result = 31 * result + parentType.hashCode(); result = 31 * result + parentType.hashCode();
result = 31 * result + Float.floatToIntBits(getBoost());
return result; return result;
} }
@ -131,7 +135,7 @@ public class ParentQuery extends Query {
if (uidToScore.v().isEmpty()) { if (uidToScore.v().isEmpty()) {
uidToScore.release(); uidToScore.release();
return Queries.NO_MATCH_QUERY.createWeight(searcher); return Queries.newMatchNoDocsQuery().createWeight(searcher);
} }
ChildWeight childWeight = new ChildWeight(parentQuery.createWeight(searcher), searchContext, uidToScore); ChildWeight childWeight = new ChildWeight(parentQuery.createWeight(searcher), searchContext, uidToScore);

View File

@ -230,6 +230,9 @@ public class TopChildrenQuery extends Query {
if (incrementalFactor != that.incrementalFactor) { if (incrementalFactor != that.incrementalFactor) {
return false; return false;
} }
if (getBoost() != that.getBoost()) {
return false;
}
return true; return true;
} }
@ -238,6 +241,7 @@ public class TopChildrenQuery extends Query {
int result = originalChildQuery.hashCode(); int result = originalChildQuery.hashCode();
result = 31 * result + parentType.hashCode(); result = 31 * result + parentType.hashCode();
result = 31 * result + incrementalFactor; result = 31 * result + incrementalFactor;
result = 31 * result + Float.floatToIntBits(getBoost());
return result; return result;
} }
@ -342,10 +346,7 @@ public class TopChildrenQuery extends Query {
@Override @Override
public final int advance(int target) throws IOException { public final int advance(int target) throws IOException {
int doc; return slowAdvance(target);
while ((doc = nextDoc()) < target) {
}
return doc;
} }
@Override @Override

View File

@ -129,6 +129,8 @@ public class QueryFacetExecutor extends FacetExecutor {
if (constantScoreQuery.getFilter() != null) { if (constantScoreQuery.getFilter() != null) {
return constantScoreQuery.getFilter(); return constantScoreQuery.getFilter();
} }
} else if (query instanceof XLuceneConstantScoreQuery) {
return ((XLuceneConstantScoreQuery) query).getFilter();
} }
return null; return null;
} }

View File

@ -34,7 +34,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* * Context-aware extension of {@link IndexSearcher}.
*/ */
public class ContextIndexSearcher extends IndexSearcher { public class ContextIndexSearcher extends IndexSearcher {
@ -43,6 +43,11 @@ public class ContextIndexSearcher extends IndexSearcher {
MAIN_QUERY MAIN_QUERY
} }
/** The wrapped {@link IndexSearcher}. The reason why we sometimes prefer delegating to this searcher instead of <tt>super</tt> is that
* this instance may have more assertions, for example if it comes from MockRobinEngine which wraps the IndexSearcher into an
* AssertingIndexSearcher. */
private final IndexSearcher in;
private final SearchContext searchContext; private final SearchContext searchContext;
private CachedDfSource dfSource; private CachedDfSource dfSource;
@ -56,6 +61,7 @@ public class ContextIndexSearcher extends IndexSearcher {
public ContextIndexSearcher(SearchContext searchContext, Engine.Searcher searcher) { public ContextIndexSearcher(SearchContext searchContext, Engine.Searcher searcher) {
super(searcher.reader()); super(searcher.reader());
in = searcher.searcher();
this.searchContext = searchContext; this.searchContext = searchContext;
setSimilarity(searcher.searcher().getSimilarity()); setSimilarity(searcher.searcher().getSimilarity());
} }
@ -106,11 +112,11 @@ public class ContextIndexSearcher extends IndexSearcher {
if (searchContext.queryRewritten()) { if (searchContext.queryRewritten()) {
return searchContext.query(); return searchContext.query();
} }
Query rewriteQuery = super.rewrite(original); Query rewriteQuery = in.rewrite(original);
searchContext.updateRewriteQuery(rewriteQuery); searchContext.updateRewriteQuery(rewriteQuery);
return rewriteQuery; return rewriteQuery;
} else { } else {
return super.rewrite(original); return in.rewrite(original);
} }
} }
@ -121,7 +127,7 @@ public class ContextIndexSearcher extends IndexSearcher {
if (dfSource != null && (query == searchContext.query() || query == searchContext.parsedQuery().query())) { if (dfSource != null && (query == searchContext.query() || query == searchContext.parsedQuery().query())) {
return dfSource.createNormalizedWeight(query); return dfSource.createNormalizedWeight(query);
} }
return super.createNormalizedWeight(query); return in.createNormalizedWeight(query);
} catch (Throwable t) { } catch (Throwable t) {
searchContext.clearReleasables(); searchContext.clearReleasables();
throw new RuntimeException(t); throw new RuntimeException(t);

View File

@ -24,10 +24,10 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField; import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*; import org.apache.lucene.index.*;
import org.apache.lucene.queries.TermFilter; import org.apache.lucene.queries.TermFilter;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Filter; import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.XLuceneConstantScoreQuery;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.store.RAMDirectory;
import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.lucene.Lucene;
@ -41,7 +41,6 @@ import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import static org.elasticsearch.common.settings.ImmutableSettings.Builder.EMPTY_SETTINGS; import static org.elasticsearch.common.settings.ImmutableSettings.Builder.EMPTY_SETTINGS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
/** /**
@ -68,7 +67,7 @@ public class FilterCacheTests extends ElasticsearchTestCase {
reader = refreshReader(reader); reader = refreshReader(reader);
IndexSearcher searcher = new IndexSearcher(reader); IndexSearcher searcher = new IndexSearcher(reader);
assertThat(Lucene.count(searcher, new ConstantScoreQuery(filterCache.cache(new TermFilter(new Term("id", "1"))))), equalTo(1l)); assertThat(Lucene.count(searcher, new XLuceneConstantScoreQuery(filterCache.cache(new TermFilter(new Term("id", "1"))))), equalTo(1l));
assertThat(Lucene.count(searcher, new XFilteredQuery(new MatchAllDocsQuery(), filterCache.cache(new TermFilter(new Term("id", "1"))))), equalTo(1l)); assertThat(Lucene.count(searcher, new XFilteredQuery(new MatchAllDocsQuery(), filterCache.cache(new TermFilter(new Term("id", "1"))))), equalTo(1l));
indexWriter.deleteDocuments(new Term("id", "1")); indexWriter.deleteDocuments(new Term("id", "1"));
@ -78,7 +77,7 @@ public class FilterCacheTests extends ElasticsearchTestCase {
Filter cachedFilter = filterCache.cache(filter); Filter cachedFilter = filterCache.cache(filter);
long constantScoreCount = filter == cachedFilter ? 0 : 1; long constantScoreCount = filter == cachedFilter ? 0 : 1;
// sadly, when caching based on cacheKey with NRT, this fails, that's why we have DeletionAware one // sadly, when caching based on cacheKey with NRT, this fails, that's why we have DeletionAware one
assertThat(Lucene.count(searcher, new ConstantScoreQuery(cachedFilter)), equalTo(constantScoreCount)); assertThat(Lucene.count(searcher, new XLuceneConstantScoreQuery(cachedFilter)), equalTo(constantScoreCount));
assertThat(Lucene.count(searcher, new XConstantScoreQuery(cachedFilter)), equalTo(0l)); assertThat(Lucene.count(searcher, new XConstantScoreQuery(cachedFilter)), equalTo(0l));
assertThat(Lucene.count(searcher, new XFilteredQuery(new MatchAllDocsQuery(), cachedFilter)), equalTo(0l)); assertThat(Lucene.count(searcher, new XFilteredQuery(new MatchAllDocsQuery(), cachedFilter)), equalTo(0l));

View File

@ -317,8 +317,8 @@ public class SimpleIndexQueryParserTests extends ElasticsearchTestCase {
IndexQueryParserService queryParser = queryParser(); IndexQueryParserService queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/starColonStar.json"); String query = copyToStringFromClasspath("/org/elasticsearch/index/query/starColonStar.json");
Query parsedQuery = queryParser.parse(query).query(); Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(ConstantScoreQuery.class)); assertThat(parsedQuery, instanceOf(XLuceneConstantScoreQuery.class));
ConstantScoreQuery constantScoreQuery = (ConstantScoreQuery) parsedQuery; XLuceneConstantScoreQuery constantScoreQuery = (XLuceneConstantScoreQuery) parsedQuery;
Filter internalFilter = constantScoreQuery.getFilter(); Filter internalFilter = constantScoreQuery.getFilter();
assertThat(internalFilter, instanceOf(MatchAllDocsFilter.class)); assertThat(internalFilter, instanceOf(MatchAllDocsFilter.class));
} }