refactor updateMinCompetitiveScore and ensures that the recorded min competitive score is resetted on setScorer

This commit is contained in:
jimczi 2019-10-01 12:32:23 +02:00
parent ee50a3812c
commit 7eab6ebb27
4 changed files with 195 additions and 190 deletions

View File

@ -124,7 +124,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
@Override @Override
public void setScorer(Scorable scorer) throws IOException { public void setScorer(Scorable scorer) throws IOException {
super.setScorer(scorer); super.setScorer(scorer);
updateMinCompetitiveScore(scorer); // reset the minimum competitive score
minCompetitiveScore = 0f;
updateMinCompetitiveScore(scorer, true);
} }
@Override @Override
@ -143,10 +145,8 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
} else { } else {
collectedAllCompetitiveHits = true; collectedAllCompetitiveHits = true;
} }
} else if (totalHitsRelation == Relation.EQUAL_TO || shouldUpdateMinScore()) { } else {
// we just reached totalHitsThreshold, we can start setting the min updateMinCompetitiveScore(scorer, totalHitsRelation == Relation.EQUAL_TO);
// competitive score now
updateMinCompetitiveScore(scorer);
} }
return; return;
} }
@ -155,7 +155,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
comparator.copy(bottom.slot, doc); comparator.copy(bottom.slot, doc);
updateBottom(doc); updateBottom(doc);
comparator.setBottom(bottom.slot); comparator.setBottom(bottom.slot);
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} else { } else {
// Startup transient: queue hasn't gathered numHits yet // Startup transient: queue hasn't gathered numHits yet
final int slot = totalHits - 1; final int slot = totalHits - 1;
@ -165,7 +165,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
add(slot, doc); add(slot, doc);
if (queueFull) { if (queueFull) {
comparator.setBottom(bottom.slot); comparator.setBottom(bottom.slot);
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} }
} }
} }
@ -214,7 +214,8 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
@Override @Override
public void setScorer(Scorable scorer) throws IOException { public void setScorer(Scorable scorer) throws IOException {
super.setScorer(scorer); super.setScorer(scorer);
updateMinCompetitiveScore(scorer); minCompetitiveScore = 0f;
updateMinCompetitiveScore(scorer, true);
} }
@Override @Override
@ -238,10 +239,10 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
} else { } else {
collectedAllCompetitiveHits = true; collectedAllCompetitiveHits = true;
} }
} else if (totalHitsRelation == Relation.EQUAL_TO || shouldUpdateMinScore()) { } else {
// we just reached totalHitsThreshold, we can start setting the min // we just reached totalHitsThreshold, we can start setting the min
// competitive score now // competitive score now
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, totalHitsRelation == Relation.EQUAL_TO);
} }
return; return;
} }
@ -260,7 +261,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
updateBottom(doc); updateBottom(doc);
comparator.setBottom(bottom.slot); comparator.setBottom(bottom.slot);
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} else { } else {
collectedHits++; collectedHits++;
@ -274,7 +275,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
queueFull = collectedHits == numHits; queueFull = collectedHits == numHits;
if (queueFull) { if (queueFull) {
comparator.setBottom(bottom.slot); comparator.setBottom(bottom.slot);
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} }
} }
} }
@ -290,10 +291,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
final BottomValueChecker bottomValueChecker; final BottomValueChecker bottomValueChecker;
final FieldComparator.RelevanceComparator firstComparator; final FieldComparator.RelevanceComparator firstComparator;
final boolean canSetMinScore; final boolean canSetMinScore;
// the minimum score (if canSetMinScore is true) that is currently used by the scorer, // the minimum competitive score (if canSetMinScore is true) that is currently
// can be different than pqTop.score if the provided bottomValueChecker reports a minimum // used by the underlying scorer (see setScorer)
// score that is greater than the local one. float minCompetitiveScore;
float minScore;
final int numComparators; final int numComparators;
FieldValueHitQueue.Entry bottom = null; FieldValueHitQueue.Entry bottom = null;
boolean queueFull; boolean queueFull;
@ -335,28 +335,31 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
return scoreMode; return scoreMode;
} }
protected boolean shouldUpdateMinScore() { protected void updateMinCompetitiveScore(Scorable scorer, boolean checkQueue) throws IOException {
return bottomValueChecker != null ? bottomValueChecker.getBottomValue() > minScore : false; if (canSetMinScore && hitsThresholdChecker.isThresholdReached()) {
} boolean hasChanged = false;
if (checkQueue && queueFull) {
protected void updateMinCompetitiveScore(Scorable scorer) throws IOException {
if (canSetMinScore && hitsThresholdChecker.isThresholdReached()
&& (queueFull || (bottomValueChecker != null && bottomValueChecker.getBottomValue() > 0f))) {
float maxMinScore = Float.NEGATIVE_INFINITY;
if (queueFull) {
assert bottom != null && firstComparator != null; assert bottom != null && firstComparator != null;
maxMinScore = firstComparator.value(bottom.slot); float localMinScore = firstComparator.value(bottom.slot);
if (bottomValueChecker != null) { if (localMinScore > minCompetitiveScore) {
bottomValueChecker.updateThreadLocalBottomValue(maxMinScore); hasChanged = true;
minCompetitiveScore = localMinScore;
if (bottomValueChecker != null) {
bottomValueChecker.updateThreadLocalBottomValue(minCompetitiveScore);
}
} }
} }
if (bottomValueChecker != null) { if (bottomValueChecker != null) {
maxMinScore = Math.max(maxMinScore, bottomValueChecker.getBottomValue()); float globalMinScore = bottomValueChecker.getBottomValue();
if (globalMinScore > minCompetitiveScore) {
hasChanged = true;
minCompetitiveScore = globalMinScore;
}
}
if (hasChanged) {
scorer.setMinCompetitiveScore(minCompetitiveScore);
totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
} }
assert maxMinScore > 0f;
scorer.setMinCompetitiveScore(maxMinScore);
minScore = maxMinScore;
totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
} }
} }

View File

@ -62,7 +62,9 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
@Override @Override
public void setScorer(Scorable scorer) throws IOException { public void setScorer(Scorable scorer) throws IOException {
super.setScorer(scorer); super.setScorer(scorer);
updateMinCompetitiveScore(scorer); // reset the minimum competitive score
minCompetitiveScore = 0f;
updateMinCompetitiveScore(scorer, true);
} }
@Override @Override
@ -76,12 +78,10 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
hitsThresholdChecker.incrementHitCount(); hitsThresholdChecker.incrementHitCount();
if (score <= pqTop.score) { if (score <= pqTop.score) {
if ((totalHitsRelation == TotalHits.Relation.EQUAL_TO || shouldUpdateMinScore()) // the document is not competitive but we need to update the minimum competitive score
&& hitsThresholdChecker.isThresholdReached()) { // if we just reached the total hits threshold or if the global minimum score (bottomValueChecker)
// we just reached totalHitsThreshold, we can start setting the min // has been updated
// competitive score now updateMinCompetitiveScore(scorer, totalHitsRelation == TotalHits.Relation.EQUAL_TO);
updateMinCompetitiveScore(scorer);
}
// Since docs are returned in-order (i.e., increasing doc Id), a document // Since docs are returned in-order (i.e., increasing doc Id), a document
// with equal score to pqTop.score cannot compete since HitQueue favors // with equal score to pqTop.score cannot compete since HitQueue favors
// documents with lower doc Ids. Therefore reject those docs too. // documents with lower doc Ids. Therefore reject those docs too.
@ -90,7 +90,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
pqTop.doc = doc + docBase; pqTop.doc = doc + docBase;
pqTop.score = score; pqTop.score = score;
pqTop = pq.updateTop(); pqTop = pq.updateTop();
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} }
}; };
@ -140,12 +140,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
if (score > after.score || (score == after.score && doc <= afterDoc)) { if (score > after.score || (score == after.score && doc <= afterDoc)) {
// hit was collected on a previous page // hit was collected on a previous page
if ((totalHitsRelation == TotalHits.Relation.EQUAL_TO || shouldUpdateMinScore()) updateMinCompetitiveScore(scorer, totalHitsRelation == TotalHits.Relation.EQUAL_TO);
&& hitsThresholdChecker.isThresholdReached()) {
// we just reached totalHitsThreshold, we can start setting the min
// competitive score now
updateMinCompetitiveScore(scorer);
}
return; return;
} }
@ -159,7 +154,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
pqTop.doc = doc + docBase; pqTop.doc = doc + docBase;
pqTop.score = score; pqTop.score = score;
pqTop = pq.updateTop(); pqTop = pq.updateTop();
updateMinCompetitiveScore(scorer); updateMinCompetitiveScore(scorer, true);
} }
}; };
} }
@ -249,10 +244,9 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
} }
ScoreDoc pqTop; ScoreDoc pqTop;
// the minimum score that is currently used by the scorer, can be different than pqTop.score // the minimum competitive score that is currently
// if the provided bottomValueChecker reports a minimum score that is greater than the local // used by the underlying scorer (see setScorer)
// one. float minCompetitiveScore;
float minScore;
final HitsThresholdChecker hitsThresholdChecker; final HitsThresholdChecker hitsThresholdChecker;
final BottomValueChecker bottomValueChecker; final BottomValueChecker bottomValueChecker;
@ -283,36 +277,44 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
return hitsThresholdChecker.scoreMode(); return hitsThresholdChecker.scoreMode();
} }
protected boolean shouldUpdateMinScore() { public boolean isQueueFull() {
return bottomValueChecker != null ? bottomValueChecker.getBottomValue() > minScore : false; return pqTop != null && pqTop.score != Float.NEGATIVE_INFINITY;
} }
protected void updateMinCompetitiveScore(Scorable scorer) throws IOException { protected void updateMinCompetitiveScore(Scorable scorer, boolean checkQueue) throws IOException {
if (hitsThresholdChecker.isThresholdReached() if (hitsThresholdChecker.isThresholdReached()) {
&& ((bottomValueChecker != null && bottomValueChecker.getBottomValue() > 0) boolean hasChanged = false;
|| (pqTop != null && pqTop.score != Float.NEGATIVE_INFINITY))) { // -Infinity is the score of sentinels if (checkQueue && isQueueFull()) {
// since we tie-break on doc id and collect in doc id order, we can require // since we tie-break on doc id and collect in doc id order, we can require
// the next float // the next float
float bottomScore = Float.NEGATIVE_INFINITY; float localMinScore = Math.nextUp(pqTop.score);
if (localMinScore > minCompetitiveScore) {
if (pqTop != null && pqTop.score != Float.NEGATIVE_INFINITY) { hasChanged = true;
bottomScore = Math.nextUp(pqTop.score); minCompetitiveScore = localMinScore;
if (bottomValueChecker != null) {
if (bottomValueChecker != null) { // we don't use the next float here since we register a minimum value
bottomValueChecker.updateThreadLocalBottomValue(pqTop.score); // for other segments that might have smaller doc ids
bottomValueChecker.updateThreadLocalBottomValue(pqTop.score);
}
} }
} }
// Global bottom can only be greater than or equal to the local bottom score // Global bottom can only be greater than or equal to the local bottom score
// The updating of global bottom score for this hit before getting here should // The updating of global bottom score for this hit before getting here should
// ensure that // ensure that
if (bottomValueChecker != null && bottomValueChecker.getBottomValue() > bottomScore) { if (bottomValueChecker != null) {
bottomScore = bottomValueChecker.getBottomValue(); float globalMinScore = bottomValueChecker.getBottomValue();
if (globalMinScore > minCompetitiveScore) {
assert isQueueFull() == false || bottomValueChecker.getBottomValue() > Math.nextUp(pqTop.score);
hasChanged = true;
minCompetitiveScore = bottomValueChecker.getBottomValue();
}
} }
scorer.setMinCompetitiveScore(bottomScore); if (hasChanged) {
minScore = bottomScore; scorer.setMinCompetitiveScore(minCompetitiveScore);
totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO; totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
}
} }
} }
} }

View File

@ -476,7 +476,7 @@ public class TestTopDocsCollector extends LuceneTestCase {
dir.close(); dir.close();
} }
public void testConcurrentMinScoreTopScoreDocs() throws Exception { public void testConcurrentMinScore() throws Exception {
Directory dir = newDirectory(); Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE)); IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE));
Document doc = new Document(); Document doc = new Document();
@ -591,121 +591,4 @@ public class TestTopDocsCollector extends LuceneTestCase {
reader.close(); reader.close();
dir.close(); dir.close();
} }
public void testConcurrentMinScoreTopFieldDocs() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE));
Document doc = new Document();
w.addDocuments(Arrays.asList(doc, doc, doc, doc, doc));
w.flush();
w.addDocuments(Arrays.asList(doc, doc, doc, doc, doc, doc));
w.flush();
w.addDocuments(Arrays.asList(doc, doc));
w.flush();
IndexReader reader = DirectoryReader.open(w);
assertEquals(3, reader.leaves().size());
w.close();
Sort sort = new Sort(SortField.FIELD_SCORE, SortField.FIELD_DOC);
CollectorManager<TopFieldCollector, TopFieldDocs> manager =
TopFieldCollector.createSharedManager(sort, 2, null, 0);
TopFieldCollector collector = manager.newCollector();
TopFieldCollector collector2 = manager.newCollector();
assertTrue(collector.bottomValueChecker == collector2.bottomValueChecker);
BottomValueChecker minValueChecker = collector.bottomValueChecker;
ScoreAndDoc scorer = new ScoreAndDoc();
ScoreAndDoc scorer2 = new ScoreAndDoc();
LeafCollector leafCollector = collector.getLeafCollector(reader.leaves().get(0));
leafCollector.setScorer(scorer);
LeafCollector leafCollector2 = collector2.getLeafCollector(reader.leaves().get(1));
leafCollector2.setScorer(scorer2);
scorer.doc = 0;
scorer.score = 3;
leafCollector.collect(0);
scorer2.doc = 0;
scorer2.score = 6;
leafCollector2.collect(0);
scorer.doc = 1;
scorer.score = 2;
leafCollector.collect(1);
assertEquals(minValueChecker.getBottomValue(), 2f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertNull(scorer2.minCompetitiveScore);
scorer2.doc = 1;
scorer2.score = 9;
leafCollector2.collect(1);
assertEquals(minValueChecker.getBottomValue(), 6f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 6f, 0f);
scorer2.doc = 2;
scorer2.score = 7;
leafCollector2.collect(2);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer2.doc = 3;
scorer2.score = 1;
leafCollector2.collect(3);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer.doc = 2;
scorer.score = 10;
leafCollector.collect(2);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 7f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer.doc = 3;
scorer.score = 11;
leafCollector.collect(3);
assertEquals(minValueChecker.getBottomValue(), 10, 0f);
assertEquals(scorer.minCompetitiveScore, 10f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
TopFieldCollector collector3 = manager.newCollector();
LeafCollector leafCollector3 = collector3.getLeafCollector(reader.leaves().get(2));
ScoreAndDoc scorer3 = new ScoreAndDoc();
leafCollector3.setScorer(scorer3);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer3.doc = 0;
scorer3.score = 1f;
leafCollector3.collect(0);
assertEquals(minValueChecker.getBottomValue(), 10f, 0f);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer.doc = 4;
scorer.score = 11;
leafCollector.collect(4);
assertEquals(minValueChecker.getBottomValue(), 11f, 0f);
assertEquals(scorer.minCompetitiveScore, 11f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer3.doc = 1;
scorer3.score = 2f;
leafCollector3.collect(1);
assertEquals(minValueChecker.getBottomValue(), 11f, 0f);
assertEquals(scorer.minCompetitiveScore, 11f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
assertEquals(scorer3.minCompetitiveScore, 11f, 0f);
TopFieldDocs topDocs = manager.reduce(Arrays.asList(collector, collector2, collector3));
assertEquals(11, topDocs.totalHits.value);
assertEquals(new TotalHits(11, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO), topDocs.totalHits);
reader.close();
dir.close();
}
} }

View File

@ -495,4 +495,121 @@ public class TestTopFieldCollector extends LuceneTestCase {
dir.close(); dir.close();
} }
public void testConcurrentMinScore() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE));
Document doc = new Document();
w.addDocuments(Arrays.asList(doc, doc, doc, doc, doc));
w.flush();
w.addDocuments(Arrays.asList(doc, doc, doc, doc, doc, doc));
w.flush();
w.addDocuments(Arrays.asList(doc, doc));
w.flush();
IndexReader reader = DirectoryReader.open(w);
assertEquals(3, reader.leaves().size());
w.close();
Sort sort = new Sort(SortField.FIELD_SCORE, SortField.FIELD_DOC);
CollectorManager<TopFieldCollector, TopFieldDocs> manager =
TopFieldCollector.createSharedManager(sort, 2, null, 0);
TopFieldCollector collector = manager.newCollector();
TopFieldCollector collector2 = manager.newCollector();
assertTrue(collector.bottomValueChecker == collector2.bottomValueChecker);
BottomValueChecker minValueChecker = collector.bottomValueChecker;
ScoreAndDoc scorer = new ScoreAndDoc();
ScoreAndDoc scorer2 = new ScoreAndDoc();
LeafCollector leafCollector = collector.getLeafCollector(reader.leaves().get(0));
leafCollector.setScorer(scorer);
LeafCollector leafCollector2 = collector2.getLeafCollector(reader.leaves().get(1));
leafCollector2.setScorer(scorer2);
scorer.doc = 0;
scorer.score = 3;
leafCollector.collect(0);
scorer2.doc = 0;
scorer2.score = 6;
leafCollector2.collect(0);
scorer.doc = 1;
scorer.score = 2;
leafCollector.collect(1);
assertEquals(minValueChecker.getBottomValue(), 2f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertNull(scorer2.minCompetitiveScore);
scorer2.doc = 1;
scorer2.score = 9;
leafCollector2.collect(1);
assertEquals(minValueChecker.getBottomValue(), 6f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 6f, 0f);
scorer2.doc = 2;
scorer2.score = 7;
leafCollector2.collect(2);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer2.doc = 3;
scorer2.score = 1;
leafCollector2.collect(3);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 2f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer.doc = 2;
scorer.score = 10;
leafCollector.collect(2);
assertEquals(minValueChecker.getBottomValue(), 7f, 0f);
assertEquals(scorer.minCompetitiveScore, 7f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
scorer.doc = 3;
scorer.score = 11;
leafCollector.collect(3);
assertEquals(minValueChecker.getBottomValue(), 10, 0f);
assertEquals(scorer.minCompetitiveScore, 10f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
TopFieldCollector collector3 = manager.newCollector();
LeafCollector leafCollector3 = collector3.getLeafCollector(reader.leaves().get(2));
ScoreAndDoc scorer3 = new ScoreAndDoc();
leafCollector3.setScorer(scorer3);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer3.doc = 0;
scorer3.score = 1f;
leafCollector3.collect(0);
assertEquals(minValueChecker.getBottomValue(), 10f, 0f);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer.doc = 4;
scorer.score = 11;
leafCollector.collect(4);
assertEquals(minValueChecker.getBottomValue(), 11f, 0f);
assertEquals(scorer.minCompetitiveScore, 11f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
assertEquals(scorer3.minCompetitiveScore, 10f, 0f);
scorer3.doc = 1;
scorer3.score = 2f;
leafCollector3.collect(1);
assertEquals(minValueChecker.getBottomValue(), 11f, 0f);
assertEquals(scorer.minCompetitiveScore, 11f, 0f);
assertEquals(scorer2.minCompetitiveScore, 7f, 0f);
assertEquals(scorer3.minCompetitiveScore, 11f, 0f);
TopFieldDocs topDocs = manager.reduce(Arrays.asList(collector, collector2, collector3));
assertEquals(11, topDocs.totalHits.value);
assertEquals(new TotalHits(11, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO), topDocs.totalHits);
reader.close();
dir.close();
}
} }