Index: lucene/contrib/remote/src/test/org/apache/lucene/search/TestRemoteSearchable.java =================================================================== --- lucene/contrib/remote/src/test/org/apache/lucene/search/TestRemoteSearchable.java (revision 1053391) +++ lucene/contrib/remote/src/test/org/apache/lucene/search/TestRemoteSearchable.java (working copy) @@ -122,8 +122,7 @@ Searchable[] searchables = { lookupRemote() }; Searcher searcher = new MultiSearcher(searchables); ScoreDoc[] hits = searcher.search( - new ConstantScoreQuery(new QueryWrapperFilter( - new TermQuery(new Term("test", "test")))), null, 1000).scoreDocs; + new ConstantScoreQuery(new TermQuery(new Term("test", "test"))), null, 1000).scoreDocs; assertEquals(1, hits.length); } } Index: lucene/src/java/org/apache/lucene/search/ConstantScoreAutoRewrite.java =================================================================== --- lucene/src/java/org/apache/lucene/search/ConstantScoreAutoRewrite.java (revision 1053391) +++ lucene/src/java/org/apache/lucene/search/ConstantScoreAutoRewrite.java (working copy) @@ -103,7 +103,7 @@ addClause(bq, placeholderTerm.createTerm(pendingTerms.get(sort[i], new BytesRef())), 1, 1.0f); } // Strip scores - final Query result = new ConstantScoreQuery(new QueryWrapperFilter(bq)); + final Query result = new ConstantScoreQuery(bq); result.setBoost(query.getBoost()); query.incTotalNumberOfTerms(size); return result; Index: lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java (revision 1053391) +++ lucene/src/java/org/apache/lucene/search/ConstantScoreQuery.java (working copy) @@ -35,9 +35,16 @@ */ public class ConstantScoreQuery extends Query { protected final Filter filter; + protected final Query query; + public ConstantScoreQuery(Query query) { + this.filter = null; + this.query = query; + } + public ConstantScoreQuery(Filter filter) { - this.filter=filter; + this.filter = filter; + this.query = null; } /** Returns the encapsulated filter */ @@ -45,24 +52,41 @@ return filter; } + /** Returns the encapsulated query */ + public Query getQuery() { + return query; + } + @Override public Query rewrite(IndexReader reader) throws IOException { + if (query != null) { + Query rewritten = query.rewrite(reader); + if (rewritten != query) { + rewritten = new ConstantScoreQuery(rewritten); + rewritten.setBoost(this.getBoost()); + return rewritten; + } + } return this; } @Override public void extractTerms(Set terms) { - // OK to not add any terms when used for MultiSearcher, + // OK to not add any terms when used for MultiSearcher (iff Filter), // but may not be OK for highlighting + if (query != null) + query.extractTerms(terms); } protected class ConstantWeight extends Weight { - private Similarity similarity; + private final Similarity similarity; private float queryNorm; private float queryWeight; + private final Weight innerWeight; - public ConstantWeight(Searcher searcher) { + public ConstantWeight(Searcher searcher) throws IOException { this.similarity = getSimilarity(searcher); + this.innerWeight = (query == null) ? null : query.createWeight(searcher); } @Override @@ -89,26 +113,46 @@ @Override public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer) throws IOException { - return new ConstantScorer(similarity, reader, this); + if (filter != null) { + assert query == null; + final DocIdSetIterator docIdSetIterator; + final DocIdSet docIdSet = filter.getDocIdSet(reader); + if (docIdSet == null) { + return null; + } else { + docIdSetIterator = docIdSet.iterator(); + if (docIdSetIterator == null) { + return null; + } + } + return new ConstantScorer(similarity, docIdSetIterator, this); + } else { + assert query != null && innerWeight != null; + final DocIdSetIterator docIdSetIterator = + innerWeight.scorer(reader, scoreDocsInOrder, topScorer); + if (docIdSetIterator == null) + return null; + return new ConstantScorer(similarity, docIdSetIterator, this); + } } @Override public Explanation explain(IndexReader reader, int doc) throws IOException { - ConstantScorer cs = new ConstantScorer(similarity, reader, this); - boolean exists = cs.docIdSetIterator.advance(doc) == doc; + ConstantScorer cs = (ConstantScorer) scorer(reader, true, false); + boolean exists = (cs != null && cs.docIdSetIterator.advance(doc) == doc); ComplexExplanation result = new ComplexExplanation(); if (exists) { - result.setDescription("ConstantScoreQuery(" + filter + result.setDescription("ConstantScoreQuery(" + ((query == null) ? filter : query).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("ConstantScoreQuery(" + filter + result.setDescription("ConstantScoreQuery(" + ((query == null) ? filter : query).toString() + ") doesn't match id " + doc); result.setValue(0); result.setMatch(Boolean.FALSE); @@ -120,22 +164,11 @@ protected class ConstantScorer extends Scorer { final DocIdSetIterator docIdSetIterator; final float theScore; - int doc = -1; - public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) throws IOException { + public ConstantScorer(Similarity similarity, DocIdSetIterator docIdSetIterator, Weight w) throws IOException { super(similarity,w); theScore = w.getValue(); - DocIdSet docIdSet = filter.getDocIdSet(reader); - if (docIdSet == null) { - docIdSetIterator = DocIdSet.EMPTY_DOCIDSET.iterator(); - } else { - DocIdSetIterator iter = docIdSet.iterator(); - if (iter == null) { - docIdSetIterator = DocIdSet.EMPTY_DOCIDSET.iterator(); - } else { - docIdSetIterator = iter; - } - } + this.docIdSetIterator = docIdSetIterator; } @Override @@ -157,34 +190,81 @@ public int advance(int target) throws IOException { return docIdSetIterator.advance(target); } + + private Collector wrapCollector(final Collector collector) { + return new Collector() { + @Override + public void setScorer(Scorer scorer) throws IOException { + // we must pass ourselves here!!! + collector.setScorer(ConstantScorer.this); + } + + @Override + public void collect(int doc) throws IOException { + collector.collect(doc); + } + + @Override + public void setNextReader(IndexReader reader, int docBase) throws IOException { + collector.setNextReader(reader, docBase); + } + + @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 (docIdSetIterator instanceof Scorer) { + ((Scorer) docIdSetIterator).score(wrapCollector(collector)); + } else { + super.score(collector); + } + } + + // this optimization allows out of order scoring as top scorer, + // TODO: theoretically this method should not be called because its protected and + // this class does not use it, it should be public in Scorer! + @Override + protected boolean score(Collector collector, int max, int firstDocID) throws IOException { + if (docIdSetIterator instanceof Scorer) { + return ((Scorer) docIdSetIterator).score(wrapCollector(collector), max, firstDocID); + } else { + return super.score(collector, max, firstDocID); + } + } } @Override - public Weight createWeight(Searcher searcher) { + public Weight createWeight(Searcher searcher) throws IOException { return new ConstantScoreQuery.ConstantWeight(searcher); } - /** Prints a user-readable version of this query. */ @Override public String toString(String field) { - return "ConstantScore(" + filter.toString() + ")" + return "ConstantScore(" + ((query == null) ? filter : query).toString() + ")" + (getBoost()==1.0 ? "" : "^" + getBoost()); } - /** Returns true if o is equal to this. */ @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ConstantScoreQuery)) return false; - ConstantScoreQuery other = (ConstantScoreQuery)o; - return this.getBoost()==other.getBoost() && filter.equals(other.filter); + if (!super.equals(o)) + return false; + final ConstantScoreQuery other = (ConstantScoreQuery)o; + return + ((this.filter == null) ? other.filter == null : this.filter.equals(other.filter)) && + ((this.query == null) ? other.query == null : this.query.equals(other.query)); } - /** Returns a hash code value for this object. */ @Override public int hashCode() { - // Simple add is OK since no existing filter hashcode has a float component. - return filter.hashCode() + Float.floatToIntBits(getBoost()); + return ((query == null) ? filter : query).hashCode() + 31 * super.hashCode(); } } Index: lucene/src/java/org/apache/lucene/search/MultiTermQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/MultiTermQuery.java (revision 1053391) +++ lucene/src/java/org/apache/lucene/search/MultiTermQuery.java (working copy) @@ -201,7 +201,7 @@ @Override protected void addClause(BooleanQuery topLevel, Term term, int docFreq, float boost) { - final Query q = new ConstantScoreQuery(new QueryWrapperFilter(new TermQuery(term, docFreq))); + final Query q = new ConstantScoreQuery(new TermQuery(term, docFreq)); q.setBoost(boost); topLevel.add(q, BooleanClause.Occur.SHOULD); } Index: lucene/src/java/org/apache/lucene/search/ScoringRewrite.java =================================================================== --- lucene/src/java/org/apache/lucene/search/ScoringRewrite.java (revision 1053391) +++ lucene/src/java/org/apache/lucene/search/ScoringRewrite.java (working copy) @@ -89,7 +89,7 @@ if (bq.clauses().isEmpty()) return bq; // strip the scores off - final Query result = new ConstantScoreQuery(new QueryWrapperFilter(bq)); + final Query result = new ConstantScoreQuery(bq); result.setBoost(query.getBoost()); return result; } Index: lucene/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java (revision 1053391) +++ lucene/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java (working copy) @@ -87,8 +87,8 @@ private Query extractInnerQuery(Query q) { if (q instanceof ConstantScoreQuery) { - // wrapped as ConstantScoreQuery using QueryWrapperFilter - q = ((QueryWrapperFilter) ((ConstantScoreQuery) q).getFilter()).getQuery(); + // wrapped as ConstantScoreQuery + q = ((ConstantScoreQuery) q).getQuery(); } return q; }