Introduce IndexSearcher#searchLeaf(LeafReaderContext, Weight, Collector) method (#13603)

There's a couple of places in the codebase where we extend `IndexSearcher` to customize
per leaf behaviour, and in order to do that, we need to override the entire search method
that loops through the leaves. A good example is `ScorerIndexSearcher`.

Adding a `searchLeaf` method that provides the per leaf behaviour makes those cases a little
easier to deal with.
This commit is contained in:
Luca Cavanna 2024-07-30 17:17:27 +02:00 committed by GitHub
parent 68aa629f6c
commit 30c965ea57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 56 deletions

View File

@ -259,6 +259,10 @@ API Changes
* GITHUB#13612: Hunspell: add Suggester#proceedPastRep to avoid losing relevant suggestions. (Peter Gromov) * GITHUB#13612: Hunspell: add Suggester#proceedPastRep to avoid losing relevant suggestions. (Peter Gromov)
* GITHUB#13603: Introduced `IndexSearcher#searchLeaf(LeafReaderContext, Weight, Collector)` protected method to
facilitate customizing per-leaf behavior of search without requiring to override
`search(LeafReaderContext[], Weight, Collector)` which requires overriding the entire loop across the leaves (Luca Cavanna)
New Features New Features
--------------------- ---------------------

View File

@ -674,7 +674,8 @@ public class IndexSearcher {
/** /**
* Lower-level search API. * Lower-level search API.
* *
* <p>{@link LeafCollector#collect(int)} is called for every document. <br> * <p>{@link #searchLeaf(LeafReaderContext, Weight, Collector)} is called for every leaf
* partition. <br>
* *
* <p>NOTE: this method executes the searches on all given leaves exclusively. To search across * <p>NOTE: this method executes the searches on all given leaves exclusively. To search across
* all the searchers leaves use {@link #leafContexts}. * all the searchers leaves use {@link #leafContexts}.
@ -694,6 +695,23 @@ public class IndexSearcher {
// threaded...? the Collector could be sync'd? // threaded...? the Collector could be sync'd?
// always use single thread: // always use single thread:
for (LeafReaderContext ctx : leaves) { // search each subreader for (LeafReaderContext ctx : leaves) { // search each subreader
searchLeaf(ctx, weight, collector);
}
}
/**
* Lower-level search API
*
* <p>{@link LeafCollector#collect(int)} is called for every document. <br>
*
* @param ctx the leaf to execute the search against
* @param weight to match document
* @param collector to receive hits
* @throws TooManyClauses If a query would exceed {@link IndexSearcher#getMaxClauseCount()}
* clauses.
*/
protected void searchLeaf(LeafReaderContext ctx, Weight weight, Collector collector)
throws IOException {
final LeafCollector leafCollector; final LeafCollector leafCollector;
try { try {
leafCollector = collector.getLeafCollector(ctx); leafCollector = collector.getLeafCollector(ctx);
@ -702,7 +720,7 @@ public class IndexSearcher {
CollectionTerminatedException e) { CollectionTerminatedException e) {
// there is no doc of interest in this reader context // there is no doc of interest in this reader context
// continue with the following leaf // continue with the following leaf
continue; return;
} }
ScorerSupplier scorerSupplier = weight.scorerSupplier(ctx); ScorerSupplier scorerSupplier = weight.scorerSupplier(ctx);
if (scorerSupplier != null) { if (scorerSupplier != null) {
@ -728,7 +746,6 @@ public class IndexSearcher {
// CollectionTerminatedException and TimeExceededException, but no other exception. // CollectionTerminatedException and TimeExceededException, but no other exception.
leafCollector.finish(); leafCollector.finish();
} }
}
/** /**
* Expert: called to re-write queries into primitive queries. * Expert: called to re-write queries into primitive queries.

View File

@ -43,27 +43,27 @@ import org.apache.lucene.util.BytesRef;
public class TestTopDocsMerge extends LuceneTestCase { public class TestTopDocsMerge extends LuceneTestCase {
private static class ShardSearcher extends IndexSearcher { private static class ShardSearcher extends IndexSearcher {
private final List<LeafReaderContext> ctx; private final LeafReaderContext ctx;
public ShardSearcher(LeafReaderContext ctx, IndexReaderContext parent) { public ShardSearcher(LeafReaderContext ctx, IndexReaderContext parent) {
super(parent); super(parent);
this.ctx = Collections.singletonList(ctx); this.ctx = ctx;
} }
public void search(Weight weight, Collector collector) throws IOException { public void search(Weight weight, Collector collector) throws IOException {
search(ctx, weight, collector); searchLeaf(ctx, weight, collector);
} }
public TopDocs search(Weight weight, int topN) throws IOException { public TopDocs search(Weight weight, int topN) throws IOException {
TopScoreDocCollector collector = TopScoreDocCollector collector =
new TopScoreDocCollectorManager(topN, null, Integer.MAX_VALUE, false).newCollector(); new TopScoreDocCollectorManager(topN, null, Integer.MAX_VALUE, false).newCollector();
search(ctx, weight, collector); searchLeaf(ctx, weight, collector);
return collector.topDocs(); return collector.topDocs();
} }
@Override @Override
public String toString() { public String toString() {
return "ShardSearcher(" + ctx.get(0) + ")"; return "ShardSearcher(" + ctx + ")";
} }
} }

View File

@ -1571,20 +1571,20 @@ public class TestGrouping extends LuceneTestCase {
} }
private static class ShardSearcher extends IndexSearcher { private static class ShardSearcher extends IndexSearcher {
private final List<LeafReaderContext> ctx; private final LeafReaderContext ctx;
public ShardSearcher(LeafReaderContext ctx, IndexReaderContext parent) { public ShardSearcher(LeafReaderContext ctx, IndexReaderContext parent) {
super(parent); super(parent);
this.ctx = Collections.singletonList(ctx); this.ctx = ctx;
} }
public void search(Weight weight, Collector collector) throws IOException { public void search(Weight weight, Collector collector) throws IOException {
search(ctx, weight, collector); searchLeaf(ctx, weight, collector);
} }
@Override @Override
public String toString() { public String toString() {
return "ShardSearcher(" + ctx.get(0).reader() + ")"; return "ShardSearcher(" + ctx.reader() + ")";
} }
} }
} }

View File

@ -17,7 +17,6 @@
package org.apache.lucene.tests.search; package org.apache.lucene.tests.search;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
@ -53,10 +52,8 @@ public class ScorerIndexSearcher extends IndexSearcher {
} }
@Override @Override
protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) protected void searchLeaf(LeafReaderContext ctx, Weight weight, Collector collector)
throws IOException { throws IOException {
collector.setWeight(weight);
for (LeafReaderContext ctx : leaves) { // search each subreader
// we force the use of Scorer (not BulkScorer) to make sure // we force the use of Scorer (not BulkScorer) to make sure
// that the scorer passed to LeafCollector.setScorer supports // that the scorer passed to LeafCollector.setScorer supports
// Scorer.getChildren // Scorer.getChildren
@ -75,5 +72,4 @@ public class ScorerIndexSearcher extends IndexSearcher {
} }
} }
} }
}
} }