|
@@ -38,7 +38,10 @@ import org.apache.lucene.search.Collector;
|
|
|
import org.apache.lucene.search.ConstantScoreQuery;
|
|
|
import org.apache.lucene.search.FieldComparator;
|
|
|
import org.apache.lucene.search.FieldDoc;
|
|
|
+import org.apache.lucene.search.FilterCollector;
|
|
|
+import org.apache.lucene.search.FilterLeafCollector;
|
|
|
import org.apache.lucene.search.IndexSearcher;
|
|
|
+import org.apache.lucene.search.LeafCollector;
|
|
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
|
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
|
|
import org.apache.lucene.search.Query;
|
|
@@ -64,10 +67,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
import static org.hamcrest.Matchers.anyOf;
|
|
|
import static org.hamcrest.Matchers.equalTo;
|
|
|
-import static org.hamcrest.Matchers.greaterThan;
|
|
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|
|
import static org.hamcrest.Matchers.instanceOf;
|
|
|
-import static org.hamcrest.Matchers.lessThan;
|
|
|
|
|
|
public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
|
|
@@ -412,30 +413,19 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
context.setTask(new SearchTask(123L, "", "", "", null));
|
|
|
context.sort(new SortAndFormats(sort, new DocValueFormat[] {DocValueFormat.RAW}));
|
|
|
|
|
|
- final AtomicBoolean collected = new AtomicBoolean();
|
|
|
final IndexReader reader = DirectoryReader.open(dir);
|
|
|
- IndexSearcher contextSearcher = new IndexSearcher(reader) {
|
|
|
- protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
|
|
- collected.set(true);
|
|
|
- super.search(leaves, weight, collector);
|
|
|
- }
|
|
|
- };
|
|
|
+ IndexSearcher contextSearcher = new IndexSearcher(reader);
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().totalHits, equalTo((long) numDocs));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs.length, equalTo(1));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs[0], instanceOf(FieldDoc.class));
|
|
|
FieldDoc fieldDoc = (FieldDoc) context.queryResult().topDocs().scoreDocs[0];
|
|
|
assertThat(fieldDoc.fields[0], equalTo(1));
|
|
|
|
|
|
-
|
|
|
{
|
|
|
- collected.set(false);
|
|
|
context.parsedPostFilter(new ParsedQuery(new MinDocQuery(1)));
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
+ assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().totalHits, equalTo(numDocs - 1L));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs.length, equalTo(1));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs[0], instanceOf(FieldDoc.class));
|
|
@@ -444,10 +434,8 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
|
|
|
final TotalHitCountCollector totalHitCountCollector = new TotalHitCountCollector();
|
|
|
context.queryCollectors().put(TotalHitCountCollector.class, totalHitCountCollector);
|
|
|
- collected.set(false);
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
+ assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().totalHits, equalTo((long) numDocs));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs.length, equalTo(1));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs[0], instanceOf(FieldDoc.class));
|
|
@@ -457,27 +445,19 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
}
|
|
|
|
|
|
{
|
|
|
- collected.set(false);
|
|
|
+ contextSearcher = getAssertingEarlyTerminationSearcher(reader, 1);
|
|
|
context.trackTotalHits(false);
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
- assertThat(context.queryResult().topDocs().totalHits, lessThan((long) numDocs));
|
|
|
+ assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs.length, equalTo(1));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs[0], instanceOf(FieldDoc.class));
|
|
|
assertThat(fieldDoc.fields[0], anyOf(equalTo(1), equalTo(2)));
|
|
|
|
|
|
- final TotalHitCountCollector totalHitCountCollector = new TotalHitCountCollector();
|
|
|
- context.queryCollectors().put(TotalHitCountCollector.class, totalHitCountCollector);
|
|
|
- collected.set(false);
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
- assertThat(context.queryResult().topDocs().totalHits, lessThan((long) numDocs));
|
|
|
+ assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs.length, equalTo(1));
|
|
|
assertThat(context.queryResult().topDocs().scoreDocs[0], instanceOf(FieldDoc.class));
|
|
|
assertThat(fieldDoc.fields[0], anyOf(equalTo(1), equalTo(2)));
|
|
|
- assertThat(totalHitCountCollector.getTotalHits(), equalTo(numDocs));
|
|
|
}
|
|
|
reader.close();
|
|
|
dir.close();
|
|
@@ -498,8 +478,9 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
doc.add(new NumericDocValuesField("tiebreaker", i));
|
|
|
w.addDocument(doc);
|
|
|
}
|
|
|
- // Make sure that we can early terminate queries on this index
|
|
|
- w.forceMerge(3);
|
|
|
+ if (randomBoolean()) {
|
|
|
+ w.forceMerge(randomIntBetween(1, 10));
|
|
|
+ }
|
|
|
w.close();
|
|
|
|
|
|
TestSearchContext context = new TestSearchContext(null, indexShard);
|
|
@@ -513,28 +494,21 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
context.setSize(10);
|
|
|
context.sort(new SortAndFormats(sort, new DocValueFormat[] {DocValueFormat.RAW, DocValueFormat.RAW}));
|
|
|
|
|
|
- final AtomicBoolean collected = new AtomicBoolean();
|
|
|
final IndexReader reader = DirectoryReader.open(dir);
|
|
|
- IndexSearcher contextSearcher = new IndexSearcher(reader) {
|
|
|
- protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
|
|
- collected.set(true);
|
|
|
- super.search(leaves, weight, collector);
|
|
|
- }
|
|
|
- };
|
|
|
+ IndexSearcher contextSearcher = new IndexSearcher(reader);
|
|
|
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
assertThat(context.queryResult().topDocs().totalHits, equalTo((long) numDocs));
|
|
|
- assertTrue(collected.get());
|
|
|
assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.terminateAfter(), equalTo(0));
|
|
|
assertThat(context.queryResult().getTotalHits(), equalTo((long) numDocs));
|
|
|
int sizeMinus1 = context.queryResult().topDocs().scoreDocs.length - 1;
|
|
|
FieldDoc lastDoc = (FieldDoc) context.queryResult().topDocs().scoreDocs[sizeMinus1];
|
|
|
|
|
|
+ contextSearcher = getAssertingEarlyTerminationSearcher(reader, 10);
|
|
|
QueryPhase.execute(context, contextSearcher, checkCancelled -> {}, sort);
|
|
|
+ assertNull(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.queryResult().topDocs().totalHits, equalTo((long) numDocs));
|
|
|
- assertTrue(collected.get());
|
|
|
- assertTrue(context.queryResult().terminatedEarly());
|
|
|
assertThat(context.terminateAfter(), equalTo(0));
|
|
|
assertThat(context.queryResult().getTotalHits(), equalTo((long) numDocs));
|
|
|
FieldDoc firstDoc = (FieldDoc) context.queryResult().topDocs().scoreDocs[0];
|
|
@@ -551,4 +525,37 @@ public class QueryPhaseTests extends IndexShardTestCase {
|
|
|
reader.close();
|
|
|
dir.close();
|
|
|
}
|
|
|
+
|
|
|
+ static IndexSearcher getAssertingEarlyTerminationSearcher(IndexReader reader, int size) {
|
|
|
+ return new IndexSearcher(reader) {
|
|
|
+ protected void search(List<LeafReaderContext> leaves, Weight weight, Collector collector) throws IOException {
|
|
|
+ final Collector in = new AssertingEalyTerminationFilterCollector(collector, size);
|
|
|
+ super.search(leaves, weight, in);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class AssertingEalyTerminationFilterCollector extends FilterCollector {
|
|
|
+ private final int size;
|
|
|
+
|
|
|
+ AssertingEalyTerminationFilterCollector(Collector in, int size) {
|
|
|
+ super(in);
|
|
|
+ this.size = size;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
|
|
+ final LeafCollector in = super.getLeafCollector(context);
|
|
|
+ return new FilterLeafCollector(in) {
|
|
|
+ int collected;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void collect(int doc) throws IOException {
|
|
|
+ assert collected <= size : "should not collect more than " + size + " doc per segment, got " + collected;
|
|
|
+ ++ collected;
|
|
|
+ super.collect(doc);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|