diff --git lucene/core/src/java/org/apache/lucene/search/CachingCollector.java lucene/core/src/java/org/apache/lucene/search/CachingCollector.java index c5957d8..55c85fe 100644 --- lucene/core/src/java/org/apache/lucene/search/CachingCollector.java +++ lucene/core/src/java/org/apache/lucene/search/CachingCollector.java @@ -161,6 +161,7 @@ public abstract class CachingCollector extends FilterCollector { + "Therefore cached documents may be out-of-order."); } collect(collector, i); + collector.done(); } } diff --git lucene/core/src/java/org/apache/lucene/search/FilterLeafCollector.java lucene/core/src/java/org/apache/lucene/search/FilterLeafCollector.java index e3ae9a8..de3279c 100644 --- lucene/core/src/java/org/apache/lucene/search/FilterLeafCollector.java +++ lucene/core/src/java/org/apache/lucene/search/FilterLeafCollector.java @@ -49,6 +49,11 @@ public class FilterLeafCollector implements LeafCollector { } @Override + public void done() throws IOException { + in.done(); + } + + @Override public String toString() { return getClass().getSimpleName() + "(" + in + ")"; } diff --git lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java index 8f1a5f6..b714d96 100644 --- lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java +++ lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java @@ -617,6 +617,7 @@ public class IndexSearcher { // continue with the following leaf } } + leafCollector.done(); } } @@ -787,6 +788,7 @@ public class IndexSearcher { fakeScorer.score = scoreDoc.score; collector.collect(scoreDoc.doc-base); } + collector.done(); // Carry over maxScore from sub: if (doMaxScore && docs.getMaxScore() > hq.maxScore) { diff --git lucene/core/src/java/org/apache/lucene/search/LeafCollector.java lucene/core/src/java/org/apache/lucene/search/LeafCollector.java index 562e76d..f326747 100644 --- lucene/core/src/java/org/apache/lucene/search/LeafCollector.java +++ lucene/core/src/java/org/apache/lucene/search/LeafCollector.java @@ -118,4 +118,9 @@ public interface LeafCollector { */ boolean acceptsDocsOutOfOrder(); + /** + * Advise that collection on this leaf has completed. + */ + void done() throws IOException; + } diff --git lucene/core/src/java/org/apache/lucene/search/MultiCollector.java lucene/core/src/java/org/apache/lucene/search/MultiCollector.java index 859b893..e7696a1 100644 --- lucene/core/src/java/org/apache/lucene/search/MultiCollector.java +++ lucene/core/src/java/org/apache/lucene/search/MultiCollector.java @@ -136,6 +136,13 @@ public class MultiCollector implements Collector { return true; } + @Override + public void done() throws IOException { + for (LeafCollector c : collectors) { + c.done(); + } + } + } } diff --git lucene/core/src/java/org/apache/lucene/search/SimpleCollector.java lucene/core/src/java/org/apache/lucene/search/SimpleCollector.java index 5803b2e..0b2cf08 100644 --- lucene/core/src/java/org/apache/lucene/search/SimpleCollector.java +++ lucene/core/src/java/org/apache/lucene/search/SimpleCollector.java @@ -50,4 +50,9 @@ public abstract class SimpleCollector implements Collector, LeafCollector { @Override public abstract void collect(int doc) throws IOException; + @Override + public void done() throws IOException { + // no-op by default + } + } diff --git lucene/core/src/java/org/apache/lucene/search/SortRescorer.java lucene/core/src/java/org/apache/lucene/search/SortRescorer.java index 6f125e8..de5e9cf 100644 --- lucene/core/src/java/org/apache/lucene/search/SortRescorer.java +++ lucene/core/src/java/org/apache/lucene/search/SortRescorer.java @@ -63,6 +63,7 @@ public class SortRescorer extends Rescorer { FakeScorer fakeScorer = new FakeScorer(); + LeafCollector leafCollector = null; while (hitUpto < hits.length) { ScoreDoc hit = hits[hitUpto]; int docID = hit.doc; @@ -75,19 +76,26 @@ public class SortRescorer extends Rescorer { if (readerContext != null) { // We advanced to another segment: - collector.getLeafCollector(readerContext); - collector.setScorer(fakeScorer); + if (leafCollector != null) { + leafCollector.done(); + } + leafCollector = collector.getLeafCollector(readerContext); + leafCollector.setScorer(fakeScorer); docBase = readerContext.docBase; } fakeScorer.score = hit.score; fakeScorer.doc = docID - docBase; - collector.collect(fakeScorer.doc); + leafCollector.collect(fakeScorer.doc); hitUpto++; } + if (leafCollector != null) { + leafCollector.done(); + } + return collector.topDocs(); } diff --git lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java index 5a7df3c..f524e6a 100644 --- lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java +++ lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java @@ -33,6 +33,7 @@ public class MultiCollectorTest extends LuceneTestCase { boolean collectCalled = false; boolean setNextReaderCalled = false; boolean setScorerCalled = false; + boolean doneCalled = false; @Override public boolean acceptsDocsOutOfOrder() { @@ -55,6 +56,11 @@ public class MultiCollectorTest extends LuceneTestCase { setScorerCalled = true; } + @Override + public void done() throws IOException { + doneCalled = true; + } + } @Test @@ -97,14 +103,17 @@ public class MultiCollectorTest extends LuceneTestCase { LeafCollector ac = c.getLeafCollector(null); assertTrue(ac.acceptsDocsOutOfOrder()); ac.collect(1); + ac.done(); ac = c.getLeafCollector(null); ac.setScorer(null); + ac.done(); for (DummyCollector dc : dcs) { assertTrue(dc.acceptsDocsOutOfOrderCalled); assertTrue(dc.collectCalled); assertTrue(dc.setNextReaderCalled); assertTrue(dc.setScorerCalled); + assertTrue(dc.doneCalled); } } diff --git lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java index e842909..8957cf3 100644 --- lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java +++ lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java @@ -81,6 +81,8 @@ public class TestCachingCollector extends LuceneTestCase { acc.collect(i); } + acc.done(); + // now replay them cc.replay(new SimpleCollector() { int prevDocID = -1; @@ -108,6 +110,8 @@ public class TestCachingCollector extends LuceneTestCase { for (int i = 0; i < 130; i++) { acc.collect(i); } + + acc.done(); assertFalse("CachingCollector should not be cached due to low memory limit", cc.isCached()); @@ -136,6 +140,7 @@ public class TestCachingCollector extends LuceneTestCase { acc = cc.getLeafCollector(null); acc.setScorer(new MockScorer()); for (int i = 0; i < 10; i++) acc.collect(i); + acc.done(); cc.replay(new NoOpCollector(true)); // this call should not fail try { cc.replay(new NoOpCollector(false)); // this call should fail @@ -164,6 +169,8 @@ public class TestCachingCollector extends LuceneTestCase { // The 151's document should terminate caching acc.collect(numDocs); assertFalse(cc.isCached()); + + acc.done(); } } @@ -174,6 +181,7 @@ public class TestCachingCollector extends LuceneTestCase { LeafCollector acc = cc.getLeafCollector(null); acc.setScorer(new MockScorer()); acc.collect(0); + acc.done(); assertTrue(cc.isCached()); cc.replay(new NoOpCollector(true)); diff --git lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java index c856c69..b739c87 100644 --- lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java +++ lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java @@ -93,6 +93,7 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase { while (s.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) { ac.collect(0); } + ac.done(); TopDocs td = tdc.topDocs(); ScoreDoc[] sd = td.scoreDocs; assertEquals(numPositiveScores, td.totalHits); diff --git lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysScorer.java lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysScorer.java index 273b6b1..dff89ce 100644 --- lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysScorer.java +++ lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysScorer.java @@ -150,6 +150,13 @@ class DrillSidewaysScorer extends BulkScorer { doUnionScoring(collector, disis, sidewaysCollectors); } + if (drillDownLeafCollector != null) { + drillDownLeafCollector.done(); + } + for (DocsAndCost dim : dims) { + dim.sidewaysLeafCollector.done(); + } + return false; } diff --git lucene/grouping/src/java/org/apache/lucene/search/grouping/AbstractSecondPassGroupingCollector.java lucene/grouping/src/java/org/apache/lucene/search/grouping/AbstractSecondPassGroupingCollector.java index aedfa9e..ddf5922 100644 --- lucene/grouping/src/java/org/apache/lucene/search/grouping/AbstractSecondPassGroupingCollector.java +++ lucene/grouping/src/java/org/apache/lucene/search/grouping/AbstractSecondPassGroupingCollector.java @@ -115,6 +115,13 @@ public abstract class AbstractSecondPassGroupingCollector exte } @Override + public void done() throws IOException { + for (SearchGroupDocs group : groupMap.values()) { + group.collector.done(); + } + } + + @Override public boolean acceptsDocsOutOfOrder() { return false; } diff --git lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java index 7c33583..78ee446 100644 --- lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java +++ lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java @@ -350,15 +350,16 @@ public class BlockGroupingCollector extends SimpleCollector { } collector.setScorer(fakeScorer); - collector.getLeafCollector(og.readerContext); + final LeafCollector leafCollector = collector.getLeafCollector(og.readerContext); for(int docIDX=0;docIDX> iter = leafCollectors.iterator(); + iter.hasNext(); ) { + iter.next().value.done(); + } + } }; } diff --git solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java index 367a6ca..e6b52fa 100644 --- solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java +++ solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java @@ -574,6 +574,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { currentContext++; currentDocBase = contexts[currentContext].docBase; nextDocBase = currentContext+1 < contexts.length ? contexts[currentContext+1].docBase : maxDoc; + leafDelegate.done(); leafDelegate = delegate.getLeafCollector(contexts[currentContext]); leafDelegate.setScorer(dummy); } @@ -583,6 +584,8 @@ public class CollapsingQParserPlugin extends QParserPlugin { leafDelegate.collect(contextDoc); } + leafDelegate.done(); + if(delegate instanceof DelegatingCollector) { ((DelegatingCollector) delegate).finish(); } @@ -691,6 +694,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { currentContext++; currentDocBase = contexts[currentContext].docBase; nextDocBase = currentContext+1 < contexts.length ? contexts[currentContext+1].docBase : maxDoc; + leafDelegate.done(); leafDelegate = delegate.getLeafCollector(contexts[currentContext]); leafDelegate.setScorer(dummy); } @@ -700,6 +704,8 @@ public class CollapsingQParserPlugin extends QParserPlugin { leafDelegate.collect(contextDoc); } + leafDelegate.done(); + if(delegate instanceof DelegatingCollector) { ((DelegatingCollector) delegate).finish(); } diff --git solr/core/src/java/org/apache/solr/search/DelegatingCollector.java solr/core/src/java/org/apache/solr/search/DelegatingCollector.java index 06b9658..df19acc 100644 --- solr/core/src/java/org/apache/solr/search/DelegatingCollector.java +++ solr/core/src/java/org/apache/solr/search/DelegatingCollector.java @@ -69,6 +69,13 @@ public class DelegatingCollector extends SimpleCollector { } @Override + public void done() throws IOException { + if (leafDelegate != null) { + leafDelegate.done(); + } + } + + @Override protected void doSetNextReader(AtomicReaderContext context) throws IOException { this.context = context; this.docBase = context.docBase; diff --git solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java index 176c0df..e735178 100644 --- solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -946,6 +946,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn leafCollector.collect(docid); } } + + leafCollector.done(); } if(collector instanceof DelegatingCollector) { @@ -2022,17 +2024,24 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn int end=0; int readerIndex = 0; + LeafCollector leafCollector = null; while (iter.hasNext()) { int doc = iter.nextDoc(); while (doc>=end) { AtomicReaderContext leaf = leafContexts.get(readerIndex++); base = leaf.docBase; end = base + leaf.reader().maxDoc(); - topCollector.getLeafCollector(leaf); + if (leafCollector != null) { + leafCollector.done(); + } + leafCollector = topCollector.getLeafCollector(leaf); // we should never need to set the scorer given the settings for the collector } topCollector.collect(doc-base); } + if (leafCollector != null) { + leafCollector.done(); + } TopDocs topDocs = topCollector.topDocs(0, nDocs);