diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index a5f4baf6e35..4d4754f0911 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -273,6 +273,8 @@ Optimizations * SOLR-4815: Admin-UI - DIH: Let "commit" be checked by default (steffkes) +* SOLR-5002: optimize numDocs(Query,DocSet) when filterCache is null (Robert Muir) + Other Changes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java index 24e4290b3b2..02c768a5947 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -59,7 +59,10 @@ import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Collector; +import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; @@ -77,6 +80,7 @@ import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopDocsCollector; import org.apache.lucene.search.TopFieldCollector; import org.apache.lucene.search.TopScoreDocCollector; +import org.apache.lucene.search.TotalHitCountCollector; import org.apache.lucene.search.Weight; import org.apache.lucene.store.Directory; import org.apache.lucene.util.Bits; @@ -1921,10 +1925,22 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn * @throws IOException If there is a low-level I/O error. */ public int numDocs(Query a, DocSet b) throws IOException { - // Negative query if absolute value different from original - Query absQ = QueryUtils.getAbs(a); - DocSet positiveA = getPositiveDocSet(absQ); - return a==absQ ? b.intersectionSize(positiveA) : b.andNotSize(positiveA); + if (filterCache != null) { + // Negative query if absolute value different from original + Query absQ = QueryUtils.getAbs(a); + DocSet positiveA = getPositiveDocSet(absQ); + return a==absQ ? b.intersectionSize(positiveA) : b.andNotSize(positiveA); + } else { + // If there isn't a cache, then do a single filtered query + // NOTE: we cannot use FilteredQuery, because BitDocSet assumes it will never + // have deleted documents, but UninvertedField's doNegative has sets with deleted docs + TotalHitCountCollector collector = new TotalHitCountCollector(); + BooleanQuery bq = new BooleanQuery(); + bq.add(QueryUtils.makeQueryable(a), BooleanClause.Occur.MUST); + bq.add(new ConstantScoreQuery(b.getTopFilter()), BooleanClause.Occur.MUST); + super.search(bq, null, collector); + return collector.getTotalHits(); + } } /** @lucene.internal */