1 package org.apache.lucene.search;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.io.IOException;
22 import org.apache.lucene.index.IndexReader;
23 import org.apache.lucene.search.FieldValueHitQueue.Entry;
24 import org.apache.lucene.util.PriorityQueue;
27 * A {@link Collector} that sorts by {@link SortField} using
28 * {@link FieldComparator}s.
30 * See the {@link #create(org.apache.lucene.search.Sort, int, boolean, boolean, boolean, boolean)} method
31 * for instantiating a TopFieldCollector.
33 * @lucene.experimental
35 public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
37 // TODO: one optimization we could do is to pre-fill
38 // the queue with sentinel value that guaranteed to
39 // always compare lower than a real hit; this would
40 // save having to check queueFull on each insert
43 * Implements a TopFieldCollector over one SortField criteria, without
44 * tracking document scores and maxScore.
46 private static class OneComparatorNonScoringCollector extends
49 final FieldComparator comparator;
52 public OneComparatorNonScoringCollector(FieldValueHitQueue<Entry> queue,
53 int numHits, boolean fillFields) throws IOException {
54 super(queue, numHits, fillFields);
55 comparator = queue.getComparators()[0];
56 reverseMul = queue.getReverseMul()[0];
59 final void updateBottom(int doc) {
60 // bottom.score is already set to Float.NaN in add().
61 bottom.doc = docBase + doc;
62 bottom = pq.updateTop();
66 public void collect(int doc) throws IOException {
69 if ((reverseMul * comparator.compareBottom(doc)) <= 0) {
70 // since docs are visited in doc Id order, if compare is 0, it means
71 // this document is largest than anything else in the queue, and
72 // therefore not competitive.
76 // This hit is competitive - replace bottom element in queue & adjustTop
77 comparator.copy(bottom.slot, doc);
79 comparator.setBottom(bottom.slot);
81 // Startup transient: queue hasn't gathered numHits yet
82 final int slot = totalHits - 1;
83 // Copy hit into queue
84 comparator.copy(slot, doc);
85 add(slot, doc, Float.NaN);
87 comparator.setBottom(bottom.slot);
93 public void setNextReader(IndexReader reader, int docBase) throws IOException {
94 this.docBase = docBase;
95 comparator.setNextReader(reader, docBase);
99 public void setScorer(Scorer scorer) throws IOException {
100 comparator.setScorer(scorer);
106 * Implements a TopFieldCollector over one SortField criteria, without
107 * tracking document scores and maxScore, and assumes out of orderness in doc
110 private static class OutOfOrderOneComparatorNonScoringCollector extends
111 OneComparatorNonScoringCollector {
113 public OutOfOrderOneComparatorNonScoringCollector(FieldValueHitQueue<Entry> queue,
114 int numHits, boolean fillFields) throws IOException {
115 super(queue, numHits, fillFields);
119 public void collect(int doc) throws IOException {
122 // Fastmatch: return if this hit is not competitive
123 final int cmp = reverseMul * comparator.compareBottom(doc);
124 if (cmp < 0 || (cmp == 0 && doc + docBase > bottom.doc)) {
128 // This hit is competitive - replace bottom element in queue & adjustTop
129 comparator.copy(bottom.slot, doc);
131 comparator.setBottom(bottom.slot);
133 // Startup transient: queue hasn't gathered numHits yet
134 final int slot = totalHits - 1;
135 // Copy hit into queue
136 comparator.copy(slot, doc);
137 add(slot, doc, Float.NaN);
139 comparator.setBottom(bottom.slot);
145 public boolean acceptsDocsOutOfOrder() {
152 * Implements a TopFieldCollector over one SortField criteria, while tracking
153 * document scores but no maxScore.
155 private static class OneComparatorScoringNoMaxScoreCollector extends
156 OneComparatorNonScoringCollector {
160 public OneComparatorScoringNoMaxScoreCollector(FieldValueHitQueue<Entry> queue,
161 int numHits, boolean fillFields) throws IOException {
162 super(queue, numHits, fillFields);
165 final void updateBottom(int doc, float score) {
166 bottom.doc = docBase + doc;
167 bottom.score = score;
168 bottom = pq.updateTop();
172 public void collect(int doc) throws IOException {
175 if ((reverseMul * comparator.compareBottom(doc)) <= 0) {
176 // since docs are visited in doc Id order, if compare is 0, it means
177 // this document is largest than anything else in the queue, and
178 // therefore not competitive.
182 // Compute the score only if the hit is competitive.
183 final float score = scorer.score();
185 // This hit is competitive - replace bottom element in queue & adjustTop
186 comparator.copy(bottom.slot, doc);
187 updateBottom(doc, score);
188 comparator.setBottom(bottom.slot);
190 // Compute the score only if the hit is competitive.
191 final float score = scorer.score();
193 // Startup transient: queue hasn't gathered numHits yet
194 final int slot = totalHits - 1;
195 // Copy hit into queue
196 comparator.copy(slot, doc);
197 add(slot, doc, score);
199 comparator.setBottom(bottom.slot);
205 public void setScorer(Scorer scorer) throws IOException {
206 this.scorer = scorer;
207 comparator.setScorer(scorer);
213 * Implements a TopFieldCollector over one SortField criteria, while tracking
214 * document scores but no maxScore, and assumes out of orderness in doc Ids
217 private static class OutOfOrderOneComparatorScoringNoMaxScoreCollector extends
218 OneComparatorScoringNoMaxScoreCollector {
220 public OutOfOrderOneComparatorScoringNoMaxScoreCollector(
221 FieldValueHitQueue<Entry> queue, int numHits, boolean fillFields)
223 super(queue, numHits, fillFields);
227 public void collect(int doc) throws IOException {
230 // Fastmatch: return if this hit is not competitive
231 final int cmp = reverseMul * comparator.compareBottom(doc);
232 if (cmp < 0 || (cmp == 0 && doc + docBase > bottom.doc)) {
236 // Compute the score only if the hit is competitive.
237 final float score = scorer.score();
239 // This hit is competitive - replace bottom element in queue & adjustTop
240 comparator.copy(bottom.slot, doc);
241 updateBottom(doc, score);
242 comparator.setBottom(bottom.slot);
244 // Compute the score only if the hit is competitive.
245 final float score = scorer.score();
247 // Startup transient: queue hasn't gathered numHits yet
248 final int slot = totalHits - 1;
249 // Copy hit into queue
250 comparator.copy(slot, doc);
251 add(slot, doc, score);
253 comparator.setBottom(bottom.slot);
259 public boolean acceptsDocsOutOfOrder() {
266 * Implements a TopFieldCollector over one SortField criteria, with tracking
267 * document scores and maxScore.
269 private static class OneComparatorScoringMaxScoreCollector extends
270 OneComparatorNonScoringCollector {
274 public OneComparatorScoringMaxScoreCollector(FieldValueHitQueue<Entry> queue,
275 int numHits, boolean fillFields) throws IOException {
276 super(queue, numHits, fillFields);
277 // Must set maxScore to NEG_INF, or otherwise Math.max always returns NaN.
278 maxScore = Float.NEGATIVE_INFINITY;
281 final void updateBottom(int doc, float score) {
282 bottom.doc = docBase + doc;
283 bottom.score = score;
284 bottom = pq.updateTop();
288 public void collect(int doc) throws IOException {
289 final float score = scorer.score();
290 if (score > maxScore) {
295 if ((reverseMul * comparator.compareBottom(doc)) <= 0) {
296 // since docs are visited in doc Id order, if compare is 0, it means
297 // this document is largest than anything else in the queue, and
298 // therefore not competitive.
302 // This hit is competitive - replace bottom element in queue & adjustTop
303 comparator.copy(bottom.slot, doc);
304 updateBottom(doc, score);
305 comparator.setBottom(bottom.slot);
307 // Startup transient: queue hasn't gathered numHits yet
308 final int slot = totalHits - 1;
309 // Copy hit into queue
310 comparator.copy(slot, doc);
311 add(slot, doc, score);
313 comparator.setBottom(bottom.slot);
320 public void setScorer(Scorer scorer) throws IOException {
321 this.scorer = scorer;
322 super.setScorer(scorer);
327 * Implements a TopFieldCollector over one SortField criteria, with tracking
328 * document scores and maxScore, and assumes out of orderness in doc Ids
331 private static class OutOfOrderOneComparatorScoringMaxScoreCollector extends
332 OneComparatorScoringMaxScoreCollector {
334 public OutOfOrderOneComparatorScoringMaxScoreCollector(FieldValueHitQueue<Entry> queue,
335 int numHits, boolean fillFields) throws IOException {
336 super(queue, numHits, fillFields);
340 public void collect(int doc) throws IOException {
341 final float score = scorer.score();
342 if (score > maxScore) {
347 // Fastmatch: return if this hit is not competitive
348 final int cmp = reverseMul * comparator.compareBottom(doc);
349 if (cmp < 0 || (cmp == 0 && doc + docBase > bottom.doc)) {
353 // This hit is competitive - replace bottom element in queue & adjustTop
354 comparator.copy(bottom.slot, doc);
355 updateBottom(doc, score);
356 comparator.setBottom(bottom.slot);
358 // Startup transient: queue hasn't gathered numHits yet
359 final int slot = totalHits - 1;
360 // Copy hit into queue
361 comparator.copy(slot, doc);
362 add(slot, doc, score);
364 comparator.setBottom(bottom.slot);
370 public boolean acceptsDocsOutOfOrder() {
377 * Implements a TopFieldCollector over multiple SortField criteria, without
378 * tracking document scores and maxScore.
380 private static class MultiComparatorNonScoringCollector extends TopFieldCollector {
382 final FieldComparator[] comparators;
383 final int[] reverseMul;
385 public MultiComparatorNonScoringCollector(FieldValueHitQueue<Entry> queue,
386 int numHits, boolean fillFields) throws IOException {
387 super(queue, numHits, fillFields);
388 comparators = queue.getComparators();
389 reverseMul = queue.getReverseMul();
392 final void updateBottom(int doc) {
393 // bottom.score is already set to Float.NaN in add().
394 bottom.doc = docBase + doc;
395 bottom = pq.updateTop();
399 public void collect(int doc) throws IOException {
402 // Fastmatch: return if this hit is not competitive
403 for (int i = 0;; i++) {
404 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
406 // Definitely not competitive.
409 // Definitely competitive.
411 } else if (i == comparators.length - 1) {
412 // Here c=0. If we're at the last comparator, this doc is not
413 // competitive, since docs are visited in doc Id order, which means
414 // this doc cannot compete with any other document in the queue.
419 // This hit is competitive - replace bottom element in queue & adjustTop
420 for (int i = 0; i < comparators.length; i++) {
421 comparators[i].copy(bottom.slot, doc);
426 for (int i = 0; i < comparators.length; i++) {
427 comparators[i].setBottom(bottom.slot);
430 // Startup transient: queue hasn't gathered numHits yet
431 final int slot = totalHits - 1;
432 // Copy hit into queue
433 for (int i = 0; i < comparators.length; i++) {
434 comparators[i].copy(slot, doc);
436 add(slot, doc, Float.NaN);
438 for (int i = 0; i < comparators.length; i++) {
439 comparators[i].setBottom(bottom.slot);
446 public void setNextReader(IndexReader reader, int docBase) throws IOException {
447 this.docBase = docBase;
448 for (int i = 0; i < comparators.length; i++) {
449 comparators[i].setNextReader(reader, docBase);
454 public void setScorer(Scorer scorer) throws IOException {
455 // set the scorer on all comparators
456 for (int i = 0; i < comparators.length; i++) {
457 comparators[i].setScorer(scorer);
463 * Implements a TopFieldCollector over multiple SortField criteria, without
464 * tracking document scores and maxScore, and assumes out of orderness in doc
467 private static class OutOfOrderMultiComparatorNonScoringCollector extends
468 MultiComparatorNonScoringCollector {
470 public OutOfOrderMultiComparatorNonScoringCollector(FieldValueHitQueue<Entry> queue,
471 int numHits, boolean fillFields) throws IOException {
472 super(queue, numHits, fillFields);
476 public void collect(int doc) throws IOException {
479 // Fastmatch: return if this hit is not competitive
480 for (int i = 0;; i++) {
481 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
483 // Definitely not competitive.
486 // Definitely competitive.
488 } else if (i == comparators.length - 1) {
489 // This is the equals case.
490 if (doc + docBase > bottom.doc) {
491 // Definitely not competitive
498 // This hit is competitive - replace bottom element in queue & adjustTop
499 for (int i = 0; i < comparators.length; i++) {
500 comparators[i].copy(bottom.slot, doc);
505 for (int i = 0; i < comparators.length; i++) {
506 comparators[i].setBottom(bottom.slot);
509 // Startup transient: queue hasn't gathered numHits yet
510 final int slot = totalHits - 1;
511 // Copy hit into queue
512 for (int i = 0; i < comparators.length; i++) {
513 comparators[i].copy(slot, doc);
515 add(slot, doc, Float.NaN);
517 for (int i = 0; i < comparators.length; i++) {
518 comparators[i].setBottom(bottom.slot);
525 public boolean acceptsDocsOutOfOrder() {
532 * Implements a TopFieldCollector over multiple SortField criteria, with
533 * tracking document scores and maxScore.
535 private static class MultiComparatorScoringMaxScoreCollector extends MultiComparatorNonScoringCollector {
539 public MultiComparatorScoringMaxScoreCollector(FieldValueHitQueue<Entry> queue,
540 int numHits, boolean fillFields) throws IOException {
541 super(queue, numHits, fillFields);
542 // Must set maxScore to NEG_INF, or otherwise Math.max always returns NaN.
543 maxScore = Float.NEGATIVE_INFINITY;
546 final void updateBottom(int doc, float score) {
547 bottom.doc = docBase + doc;
548 bottom.score = score;
549 bottom = pq.updateTop();
553 public void collect(int doc) throws IOException {
554 final float score = scorer.score();
555 if (score > maxScore) {
560 // Fastmatch: return if this hit is not competitive
561 for (int i = 0;; i++) {
562 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
564 // Definitely not competitive.
567 // Definitely competitive.
569 } else if (i == comparators.length - 1) {
570 // Here c=0. If we're at the last comparator, this doc is not
571 // competitive, since docs are visited in doc Id order, which means
572 // this doc cannot compete with any other document in the queue.
577 // This hit is competitive - replace bottom element in queue & adjustTop
578 for (int i = 0; i < comparators.length; i++) {
579 comparators[i].copy(bottom.slot, doc);
582 updateBottom(doc, score);
584 for (int i = 0; i < comparators.length; i++) {
585 comparators[i].setBottom(bottom.slot);
588 // Startup transient: queue hasn't gathered numHits yet
589 final int slot = totalHits - 1;
590 // Copy hit into queue
591 for (int i = 0; i < comparators.length; i++) {
592 comparators[i].copy(slot, doc);
594 add(slot, doc, score);
596 for (int i = 0; i < comparators.length; i++) {
597 comparators[i].setBottom(bottom.slot);
604 public void setScorer(Scorer scorer) throws IOException {
605 this.scorer = scorer;
606 super.setScorer(scorer);
611 * Implements a TopFieldCollector over multiple SortField criteria, with
612 * tracking document scores and maxScore, and assumes out of orderness in doc
615 private final static class OutOfOrderMultiComparatorScoringMaxScoreCollector
616 extends MultiComparatorScoringMaxScoreCollector {
618 public OutOfOrderMultiComparatorScoringMaxScoreCollector(FieldValueHitQueue<Entry> queue,
619 int numHits, boolean fillFields) throws IOException {
620 super(queue, numHits, fillFields);
624 public void collect(int doc) throws IOException {
625 final float score = scorer.score();
626 if (score > maxScore) {
631 // Fastmatch: return if this hit is not competitive
632 for (int i = 0;; i++) {
633 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
635 // Definitely not competitive.
638 // Definitely competitive.
640 } else if (i == comparators.length - 1) {
641 // This is the equals case.
642 if (doc + docBase > bottom.doc) {
643 // Definitely not competitive
650 // This hit is competitive - replace bottom element in queue & adjustTop
651 for (int i = 0; i < comparators.length; i++) {
652 comparators[i].copy(bottom.slot, doc);
655 updateBottom(doc, score);
657 for (int i = 0; i < comparators.length; i++) {
658 comparators[i].setBottom(bottom.slot);
661 // Startup transient: queue hasn't gathered numHits yet
662 final int slot = totalHits - 1;
663 // Copy hit into queue
664 for (int i = 0; i < comparators.length; i++) {
665 comparators[i].copy(slot, doc);
667 add(slot, doc, score);
669 for (int i = 0; i < comparators.length; i++) {
670 comparators[i].setBottom(bottom.slot);
677 public boolean acceptsDocsOutOfOrder() {
684 * Implements a TopFieldCollector over multiple SortField criteria, with
685 * tracking document scores and maxScore.
687 private static class MultiComparatorScoringNoMaxScoreCollector extends MultiComparatorNonScoringCollector {
691 public MultiComparatorScoringNoMaxScoreCollector(FieldValueHitQueue<Entry> queue,
692 int numHits, boolean fillFields) throws IOException {
693 super(queue, numHits, fillFields);
696 final void updateBottom(int doc, float score) {
697 bottom.doc = docBase + doc;
698 bottom.score = score;
699 bottom = pq.updateTop();
703 public void collect(int doc) throws IOException {
706 // Fastmatch: return if this hit is not competitive
707 for (int i = 0;; i++) {
708 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
710 // Definitely not competitive.
713 // Definitely competitive.
715 } else if (i == comparators.length - 1) {
716 // Here c=0. If we're at the last comparator, this doc is not
717 // competitive, since docs are visited in doc Id order, which means
718 // this doc cannot compete with any other document in the queue.
723 // This hit is competitive - replace bottom element in queue & adjustTop
724 for (int i = 0; i < comparators.length; i++) {
725 comparators[i].copy(bottom.slot, doc);
728 // Compute score only if it is competitive.
729 final float score = scorer.score();
730 updateBottom(doc, score);
732 for (int i = 0; i < comparators.length; i++) {
733 comparators[i].setBottom(bottom.slot);
736 // Startup transient: queue hasn't gathered numHits yet
737 final int slot = totalHits - 1;
738 // Copy hit into queue
739 for (int i = 0; i < comparators.length; i++) {
740 comparators[i].copy(slot, doc);
743 // Compute score only if it is competitive.
744 final float score = scorer.score();
745 add(slot, doc, score);
747 for (int i = 0; i < comparators.length; i++) {
748 comparators[i].setBottom(bottom.slot);
755 public void setScorer(Scorer scorer) throws IOException {
756 this.scorer = scorer;
757 super.setScorer(scorer);
762 * Implements a TopFieldCollector over multiple SortField criteria, with
763 * tracking document scores and maxScore, and assumes out of orderness in doc
766 private final static class OutOfOrderMultiComparatorScoringNoMaxScoreCollector
767 extends MultiComparatorScoringNoMaxScoreCollector {
769 public OutOfOrderMultiComparatorScoringNoMaxScoreCollector(
770 FieldValueHitQueue<Entry> queue, int numHits, boolean fillFields)
772 super(queue, numHits, fillFields);
776 public void collect(int doc) throws IOException {
779 // Fastmatch: return if this hit is not competitive
780 for (int i = 0;; i++) {
781 final int c = reverseMul[i] * comparators[i].compareBottom(doc);
783 // Definitely not competitive.
786 // Definitely competitive.
788 } else if (i == comparators.length - 1) {
789 // This is the equals case.
790 if (doc + docBase > bottom.doc) {
791 // Definitely not competitive
798 // This hit is competitive - replace bottom element in queue & adjustTop
799 for (int i = 0; i < comparators.length; i++) {
800 comparators[i].copy(bottom.slot, doc);
803 // Compute score only if it is competitive.
804 final float score = scorer.score();
805 updateBottom(doc, score);
807 for (int i = 0; i < comparators.length; i++) {
808 comparators[i].setBottom(bottom.slot);
811 // Startup transient: queue hasn't gathered numHits yet
812 final int slot = totalHits - 1;
813 // Copy hit into queue
814 for (int i = 0; i < comparators.length; i++) {
815 comparators[i].copy(slot, doc);
818 // Compute score only if it is competitive.
819 final float score = scorer.score();
820 add(slot, doc, score);
822 for (int i = 0; i < comparators.length; i++) {
823 comparators[i].setBottom(bottom.slot);
830 public void setScorer(Scorer scorer) throws IOException {
831 this.scorer = scorer;
832 super.setScorer(scorer);
836 public boolean acceptsDocsOutOfOrder() {
842 private static final ScoreDoc[] EMPTY_SCOREDOCS = new ScoreDoc[0];
844 private final boolean fillFields;
847 * Stores the maximum score value encountered, needed for normalizing. If
848 * document scores are not tracked, this value is initialized to NaN.
850 float maxScore = Float.NaN;
853 FieldValueHitQueue.Entry bottom = null;
857 // Declaring the constructor private prevents extending this class by anyone
858 // else. Note that the class cannot be final since it's extended by the
859 // internal versions. If someone will define a constructor with any other
860 // visibility, then anyone will be able to extend the class, which is not what
862 private TopFieldCollector(PriorityQueue<Entry> pq, int numHits, boolean fillFields) {
864 this.numHits = numHits;
865 this.fillFields = fillFields;
869 * Creates a new {@link TopFieldCollector} from the given
872 * <p><b>NOTE</b>: The instances returned by this method
873 * pre-allocate a full array of length
874 * <code>numHits</code>.
877 * the sort criteria (SortFields).
879 * the number of results to collect.
881 * specifies whether the actual field values should be returned on
882 * the results (FieldDoc).
883 * @param trackDocScores
884 * specifies whether document scores should be tracked and set on the
885 * results. Note that if set to false, then the results' scores will
886 * be set to Float.NaN. Setting this to true affects performance, as
887 * it incurs the score computation on each competitive result.
888 * Therefore if document scores are not required by the application,
889 * it is recommended to set it to false.
890 * @param trackMaxScore
891 * specifies whether the query's maxScore should be tracked and set
892 * on the resulting {@link TopDocs}. Note that if set to false,
893 * {@link TopDocs#getMaxScore()} returns Float.NaN. Setting this to
894 * true affects performance as it incurs the score computation on
895 * each result. Also, setting this true automatically sets
896 * <code>trackDocScores</code> to true as well.
897 * @param docsScoredInOrder
898 * specifies whether documents are scored in doc Id order or not by
899 * the given {@link Scorer} in {@link #setScorer(Scorer)}.
900 * @return a {@link TopFieldCollector} instance which will sort the results by
902 * @throws IOException
904 public static TopFieldCollector create(Sort sort, int numHits,
905 boolean fillFields, boolean trackDocScores, boolean trackMaxScore,
906 boolean docsScoredInOrder)
908 if (sort.fields.length == 0) {
909 throw new IllegalArgumentException("Sort must contain at least one field");
913 throw new IllegalArgumentException("numHits must be > 0; please use TotalHitCountCollector if you just need the total hit count");
916 FieldValueHitQueue<Entry> queue = FieldValueHitQueue.create(sort.fields, numHits);
917 if (queue.getComparators().length == 1) {
918 if (docsScoredInOrder) {
920 return new OneComparatorScoringMaxScoreCollector(queue, numHits, fillFields);
921 } else if (trackDocScores) {
922 return new OneComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields);
924 return new OneComparatorNonScoringCollector(queue, numHits, fillFields);
928 return new OutOfOrderOneComparatorScoringMaxScoreCollector(queue, numHits, fillFields);
929 } else if (trackDocScores) {
930 return new OutOfOrderOneComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields);
932 return new OutOfOrderOneComparatorNonScoringCollector(queue, numHits, fillFields);
937 // multiple comparators.
938 if (docsScoredInOrder) {
940 return new MultiComparatorScoringMaxScoreCollector(queue, numHits, fillFields);
941 } else if (trackDocScores) {
942 return new MultiComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields);
944 return new MultiComparatorNonScoringCollector(queue, numHits, fillFields);
948 return new OutOfOrderMultiComparatorScoringMaxScoreCollector(queue, numHits, fillFields);
949 } else if (trackDocScores) {
950 return new OutOfOrderMultiComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields);
952 return new OutOfOrderMultiComparatorNonScoringCollector(queue, numHits, fillFields);
957 final void add(int slot, int doc, float score) {
958 bottom = pq.add(new Entry(slot, docBase + doc, score));
959 queueFull = totalHits == numHits;
963 * Only the following callback methods need to be overridden since
964 * topDocs(int, int) calls them to return the results.
968 protected void populateResults(ScoreDoc[] results, int howMany) {
970 // avoid casting if unnecessary.
971 FieldValueHitQueue<Entry> queue = (FieldValueHitQueue<Entry>) pq;
972 for (int i = howMany - 1; i >= 0; i--) {
973 results[i] = queue.fillFields(queue.pop());
976 for (int i = howMany - 1; i >= 0; i--) {
977 Entry entry = pq.pop();
978 results[i] = new FieldDoc(entry.doc, entry.score);
984 protected TopDocs newTopDocs(ScoreDoc[] results, int start) {
985 if (results == null) {
986 results = EMPTY_SCOREDOCS;
987 // Set maxScore to NaN, in case this is a maxScore tracking collector.
988 maxScore = Float.NaN;
991 // If this is a maxScoring tracking collector and there were no results,
992 return new TopFieldDocs(totalHits, results, ((FieldValueHitQueue<Entry>) pq).getFields(), maxScore);
996 public boolean acceptsDocsOutOfOrder() {