1 /////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2009-2014 Alan Wright. All rights reserved.
3 // Distributable under the terms of either the Apache License (Version 2.0)
4 // or the GNU Lesser General Public License.
5 /////////////////////////////////////////////////////////////////////////////
6 
7 #include "LuceneInc.h"
8 #include "TopFieldCollector.h"
9 #include "_TopFieldCollector.h"
10 #include "FieldValueHitQueue.h"
11 #include "FieldComparator.h"
12 #include "FieldDoc.h"
13 #include "Scorer.h"
14 #include "Sort.h"
15 #include "TopFieldDocs.h"
16 
17 namespace Lucene {
18 
TopFieldCollector(const HitQueueBasePtr & pq,int32_t numHits,bool fillFields)19 TopFieldCollector::TopFieldCollector(const HitQueueBasePtr& pq, int32_t numHits, bool fillFields) : TopDocsCollector(pq) {
20     this->numHits = numHits;
21     this->fillFields = fillFields;
22     this->maxScore = std::numeric_limits<double>::quiet_NaN();
23     this->queueFull = false;
24     this->docBase = 0;
25 }
26 
~TopFieldCollector()27 TopFieldCollector::~TopFieldCollector() {
28 }
29 
EMPTY_SCOREDOCS()30 const Collection<ScoreDocPtr> TopFieldCollector::EMPTY_SCOREDOCS() {
31     static Collection<ScoreDocPtr> _EMPTY_SCOREDOCS;
32     if (!_EMPTY_SCOREDOCS) {
33         _EMPTY_SCOREDOCS = Collection<ScoreDocPtr>::newInstance();
34     }
35     return _EMPTY_SCOREDOCS;
36 }
37 
create(const SortPtr & sort,int32_t numHits,bool fillFields,bool trackDocScores,bool trackMaxScore,bool docsScoredInOrder)38 TopFieldCollectorPtr TopFieldCollector::create(const SortPtr& sort, int32_t numHits, bool fillFields, bool trackDocScores, bool trackMaxScore, bool docsScoredInOrder) {
39     if (sort->fields.empty()) {
40         boost::throw_exception(IllegalArgumentException(L"Sort must contain at least one field"));
41     }
42 
43     FieldValueHitQueuePtr queue(FieldValueHitQueue::create(sort->fields, numHits));
44     if (queue->getComparators().size() == 1) {
45         if (docsScoredInOrder) {
46             if (trackMaxScore) {
47                 return newLucene<OneComparatorScoringMaxScoreCollector>(queue, numHits, fillFields);
48             } else if (trackDocScores) {
49                 return newLucene<OneComparatorScoringNoMaxScoreCollector>(queue, numHits, fillFields);
50             } else {
51                 return newLucene<OneComparatorNonScoringCollector>(queue, numHits, fillFields);
52             }
53         } else {
54             if (trackMaxScore) {
55                 return newLucene<OutOfOrderOneComparatorScoringMaxScoreCollector>(queue, numHits, fillFields);
56             } else if (trackDocScores) {
57                 return newLucene<OutOfOrderOneComparatorScoringNoMaxScoreCollector>(queue, numHits, fillFields);
58             } else {
59                 return newLucene<OutOfOrderOneComparatorNonScoringCollector>(queue, numHits, fillFields);
60             }
61         }
62     }
63 
64     // multiple comparators
65     if (docsScoredInOrder) {
66         if (trackMaxScore) {
67             return newLucene<MultiComparatorScoringMaxScoreCollector>(queue, numHits, fillFields);
68         } else if (trackDocScores) {
69             return newLucene<MultiComparatorScoringNoMaxScoreCollector>(queue, numHits, fillFields);
70         } else {
71             return newLucene<MultiComparatorNonScoringCollector>(queue, numHits, fillFields);
72         }
73     } else {
74         if (trackMaxScore) {
75             return newLucene<OutOfOrderMultiComparatorScoringMaxScoreCollector>(queue, numHits, fillFields);
76         } else if (trackDocScores) {
77             return newLucene<OutOfOrderMultiComparatorScoringNoMaxScoreCollector>(queue, numHits, fillFields);
78         } else {
79             return newLucene<OutOfOrderMultiComparatorNonScoringCollector>(queue, numHits, fillFields);
80         }
81     }
82 }
83 
add(int32_t slot,int32_t doc,double score)84 void TopFieldCollector::add(int32_t slot, int32_t doc, double score) {
85     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->add(newLucene<FieldValueHitQueueEntry>(slot, docBase + doc, score)));
86     queueFull = (totalHits == numHits);
87 }
88 
populateResults(Collection<ScoreDocPtr> results,int32_t howMany)89 void TopFieldCollector::populateResults(Collection<ScoreDocPtr> results, int32_t howMany) {
90     if (fillFields) {
91         FieldValueHitQueuePtr queue(boost::static_pointer_cast<FieldValueHitQueue>(pq));
92         for (int32_t i = howMany - 1; i >= 0; --i) {
93             results[i] = queue->fillFields(boost::static_pointer_cast<FieldValueHitQueueEntry>(queue->pop()));
94         }
95     } else {
96         for (int32_t i = howMany - 1; i >= 0; --i) {
97             FieldValueHitQueueEntryPtr entry(boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->pop()));
98             results[i] = newLucene<FieldDoc>(entry->doc, entry->score);
99         }
100     }
101 }
102 
newTopDocs(Collection<ScoreDocPtr> results,int32_t start)103 TopDocsPtr TopFieldCollector::newTopDocs(Collection<ScoreDocPtr> results, int32_t start) {
104     if (!results) {
105         results = EMPTY_SCOREDOCS();
106         // Set maxScore to NaN, in case this is a maxScore tracking collector
107         maxScore = std::numeric_limits<double>::quiet_NaN();
108     }
109 
110     // If this is a maxScoring tracking collector and there were no results
111     return newLucene<TopFieldDocs>(totalHits, results, boost::static_pointer_cast<FieldValueHitQueue>(pq)->getFields(), maxScore);
112 }
113 
acceptsDocsOutOfOrder()114 bool TopFieldCollector::acceptsDocsOutOfOrder() {
115     return false;
116 }
117 
OneComparatorNonScoringCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)118 OneComparatorNonScoringCollector::OneComparatorNonScoringCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : TopFieldCollector(queue, numHits, fillFields) {
119 }
120 
~OneComparatorNonScoringCollector()121 OneComparatorNonScoringCollector::~OneComparatorNonScoringCollector() {
122 }
123 
initialize()124 void OneComparatorNonScoringCollector::initialize() {
125     TopFieldCollector::initialize();
126     FieldValueHitQueuePtr queue(boost::static_pointer_cast<FieldValueHitQueue>(pq));
127     comparator = queue->getComparators()[0];
128     reverseMul = queue->getReverseMul()[0];
129 }
130 
updateBottom(int32_t doc)131 void OneComparatorNonScoringCollector::updateBottom(int32_t doc) {
132     // bottom.score is already set to NaN in add().
133     bottom->doc = docBase + doc;
134     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
135 }
136 
collect(int32_t doc)137 void OneComparatorNonScoringCollector::collect(int32_t doc) {
138     ++totalHits;
139     if (queueFull) {
140         if ((reverseMul * comparator->compareBottom(doc)) <= 0) {
141             // since docs are visited in doc Id order, if compare is 0, it means this document is largest
142             // than anything else in the queue, and therefore not competitive.
143             return;
144         }
145 
146         // This hit is competitive - replace bottom element in queue and adjustTop
147         comparator->copy(bottom->slot, doc);
148         updateBottom(doc);
149         comparator->setBottom(bottom->slot);
150     } else {
151         // Startup transient: queue hasn't gathered numHits yet
152         int32_t slot = totalHits - 1;
153         // Copy hit into queue
154         comparator->copy(slot, doc);
155         add(slot, doc, std::numeric_limits<double>::quiet_NaN());
156         if (queueFull) {
157             comparator->setBottom(bottom->slot);
158         }
159     }
160 }
161 
setNextReader(const IndexReaderPtr & reader,int32_t docBase)162 void OneComparatorNonScoringCollector::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
163     this->docBase = docBase;
164     comparator->setNextReader(reader, docBase);
165 }
166 
setScorer(const ScorerPtr & scorer)167 void OneComparatorNonScoringCollector::setScorer(const ScorerPtr& scorer) {
168     comparator->setScorer(scorer);
169 }
170 
OutOfOrderOneComparatorNonScoringCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)171 OutOfOrderOneComparatorNonScoringCollector::OutOfOrderOneComparatorNonScoringCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : OneComparatorNonScoringCollector(queue, numHits, fillFields) {
172 }
173 
~OutOfOrderOneComparatorNonScoringCollector()174 OutOfOrderOneComparatorNonScoringCollector::~OutOfOrderOneComparatorNonScoringCollector() {
175 }
176 
collect(int32_t doc)177 void OutOfOrderOneComparatorNonScoringCollector::collect(int32_t doc) {
178     ++totalHits;
179     if (queueFull) {
180         // Fastmatch: return if this hit is not competitive
181         int32_t cmp = reverseMul * comparator->compareBottom(doc);
182         if (cmp < 0 || (cmp == 0 && doc + docBase > bottom->doc)) {
183             return;
184         }
185 
186         // This hit is competitive - replace bottom element in queue and adjustTop
187         comparator->copy(bottom->slot, doc);
188         updateBottom(doc);
189         comparator->setBottom(bottom->slot);
190     } else {
191         // Startup transient: queue hasn't gathered numHits yet
192         int32_t slot = totalHits - 1;
193         // Copy hit into queue
194         comparator->copy(slot, doc);
195         add(slot, doc, std::numeric_limits<double>::quiet_NaN());
196         if (queueFull) {
197             comparator->setBottom(bottom->slot);
198         }
199     }
200 }
201 
acceptsDocsOutOfOrder()202 bool OutOfOrderOneComparatorNonScoringCollector::acceptsDocsOutOfOrder() {
203     return true;
204 }
205 
OneComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)206 OneComparatorScoringNoMaxScoreCollector::OneComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : OneComparatorNonScoringCollector(queue, numHits, fillFields) {
207 }
208 
~OneComparatorScoringNoMaxScoreCollector()209 OneComparatorScoringNoMaxScoreCollector::~OneComparatorScoringNoMaxScoreCollector() {
210 }
211 
updateBottom(int32_t doc,double score)212 void OneComparatorScoringNoMaxScoreCollector::updateBottom(int32_t doc, double score) {
213     bottom->doc = docBase + doc;
214     bottom->score = score;
215     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
216 }
217 
collect(int32_t doc)218 void OneComparatorScoringNoMaxScoreCollector::collect(int32_t doc) {
219     ++totalHits;
220     if (queueFull) {
221         if ((reverseMul * comparator->compareBottom(doc)) <= 0) {
222             // since docs are visited in doc Id order, if compare is 0, it means this document is largest
223             // than anything else in the queue, and therefore not competitive.
224             return;
225         }
226 
227         // Compute the score only if the hit is competitive.
228         double score = scorer->score();
229 
230         // This hit is competitive - replace bottom element in queue and adjustTop
231         comparator->copy(bottom->slot, doc);
232         updateBottom(doc, score);
233         comparator->setBottom(bottom->slot);
234     } else {
235         // Compute the score only if the hit is competitive.
236         double score = scorer->score();
237 
238         // Startup transient: queue hasn't gathered numHits yet
239         int32_t slot = totalHits - 1;
240         // Copy hit into queue
241         comparator->copy(slot, doc);
242         add(slot, doc, score);
243         if (queueFull) {
244             comparator->setBottom(bottom->slot);
245         }
246     }
247 }
248 
setScorer(const ScorerPtr & scorer)249 void OneComparatorScoringNoMaxScoreCollector::setScorer(const ScorerPtr& scorer) {
250     this->scorer = scorer;
251     comparator->setScorer(scorer);
252 }
253 
OutOfOrderOneComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)254 OutOfOrderOneComparatorScoringNoMaxScoreCollector::OutOfOrderOneComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : OneComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields) {
255 }
256 
~OutOfOrderOneComparatorScoringNoMaxScoreCollector()257 OutOfOrderOneComparatorScoringNoMaxScoreCollector::~OutOfOrderOneComparatorScoringNoMaxScoreCollector() {
258 }
259 
collect(int32_t doc)260 void OutOfOrderOneComparatorScoringNoMaxScoreCollector::collect(int32_t doc) {
261     ++totalHits;
262     if (queueFull) {
263         // Fastmatch: return if this hit is not competitive
264         int32_t cmp = reverseMul * comparator->compareBottom(doc);
265         if (cmp < 0 || (cmp == 0 && doc + docBase > bottom->doc)) {
266             return;
267         }
268 
269         // Compute the score only if the hit is competitive.
270         double score = scorer->score();
271 
272         // This hit is competitive - replace bottom element in queue and adjustTop
273         comparator->copy(bottom->slot, doc);
274         updateBottom(doc, score);
275         comparator->setBottom(bottom->slot);
276     } else {
277         // Compute the score only if the hit is competitive.
278         double score = scorer->score();
279 
280         // Startup transient: queue hasn't gathered numHits yet
281         int32_t slot = totalHits - 1;
282         // Copy hit into queue
283         comparator->copy(slot, doc);
284         add(slot, doc, score);
285         if (queueFull) {
286             comparator->setBottom(bottom->slot);
287         }
288     }
289 }
290 
acceptsDocsOutOfOrder()291 bool OutOfOrderOneComparatorScoringNoMaxScoreCollector::acceptsDocsOutOfOrder() {
292     return true;
293 }
294 
OneComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)295 OneComparatorScoringMaxScoreCollector::OneComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : OneComparatorNonScoringCollector(queue, numHits, fillFields) {
296     // Must set maxScore to NEG_INF, or otherwise std::max always returns NaN.
297     this->maxScore = -std::numeric_limits<double>::infinity();
298 }
299 
~OneComparatorScoringMaxScoreCollector()300 OneComparatorScoringMaxScoreCollector::~OneComparatorScoringMaxScoreCollector() {
301 }
302 
updateBottom(int32_t doc,double score)303 void OneComparatorScoringMaxScoreCollector::updateBottom(int32_t doc, double score) {
304     bottom->doc = docBase + doc;
305     bottom->score = score;
306     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
307 }
308 
collect(int32_t doc)309 void OneComparatorScoringMaxScoreCollector::collect(int32_t doc) {
310     double score = scorer->score();
311     if (score > maxScore) {
312         maxScore = score;
313     }
314     ++totalHits;
315     if (queueFull) {
316         if ((reverseMul * comparator->compareBottom(doc)) <= 0) {
317             // since docs are visited in doc Id order, if compare is 0, it means this document is largest
318             // than anything else in the queue, and therefore not competitive.
319             return;
320         }
321 
322         // This hit is competitive - replace bottom element in queue and adjustTop
323         comparator->copy(bottom->slot, doc);
324         updateBottom(doc, score);
325         comparator->setBottom(bottom->slot);
326     } else {
327         // Startup transient: queue hasn't gathered numHits yet
328         int32_t slot = totalHits - 1;
329         // Copy hit into queue
330         comparator->copy(slot, doc);
331         add(slot, doc, score);
332         if (queueFull) {
333             comparator->setBottom(bottom->slot);
334         }
335     }
336 }
337 
setScorer(const ScorerPtr & scorer)338 void OneComparatorScoringMaxScoreCollector::setScorer(const ScorerPtr& scorer) {
339     this->scorer = scorer;
340     OneComparatorNonScoringCollector::setScorer(scorer);
341 }
342 
OutOfOrderOneComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)343 OutOfOrderOneComparatorScoringMaxScoreCollector::OutOfOrderOneComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : OneComparatorScoringMaxScoreCollector(queue, numHits, fillFields) {
344 }
345 
~OutOfOrderOneComparatorScoringMaxScoreCollector()346 OutOfOrderOneComparatorScoringMaxScoreCollector::~OutOfOrderOneComparatorScoringMaxScoreCollector() {
347 }
348 
collect(int32_t doc)349 void OutOfOrderOneComparatorScoringMaxScoreCollector::collect(int32_t doc) {
350     double score = scorer->score();
351     if (score > maxScore) {
352         maxScore = score;
353     }
354     ++totalHits;
355     if (queueFull) {
356         // Fastmatch: return if this hit is not competitive
357         int32_t cmp = reverseMul * comparator->compareBottom(doc);
358         if (cmp < 0 || (cmp == 0 && doc + docBase > bottom->doc)) {
359             return;
360         }
361 
362         // This hit is competitive - replace bottom element in queue and adjustTop
363         comparator->copy(bottom->slot, doc);
364         updateBottom(doc, score);
365         comparator->setBottom(bottom->slot);
366     } else {
367         // Startup transient: queue hasn't gathered numHits yet
368         int32_t slot = totalHits - 1;
369         // Copy hit into queue
370         comparator->copy(slot, doc);
371         add(slot, doc, score);
372         if (queueFull) {
373             comparator->setBottom(bottom->slot);
374         }
375     }
376 }
377 
acceptsDocsOutOfOrder()378 bool OutOfOrderOneComparatorScoringMaxScoreCollector::acceptsDocsOutOfOrder() {
379     return true;
380 }
381 
MultiComparatorNonScoringCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)382 MultiComparatorNonScoringCollector::MultiComparatorNonScoringCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : TopFieldCollector(queue, numHits, fillFields) {
383 }
384 
~MultiComparatorNonScoringCollector()385 MultiComparatorNonScoringCollector::~MultiComparatorNonScoringCollector() {
386 }
387 
initialize()388 void MultiComparatorNonScoringCollector::initialize() {
389     TopFieldCollector::initialize();
390     FieldValueHitQueuePtr queue(boost::static_pointer_cast<FieldValueHitQueue>(pq));
391     comparators = queue->getComparators();
392     reverseMul = queue->getReverseMul();
393 }
394 
updateBottom(int32_t doc)395 void MultiComparatorNonScoringCollector::updateBottom(int32_t doc) {
396     // bottom.score is already set to NaN in add().
397     bottom->doc = docBase + doc;
398     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
399 }
400 
collect(int32_t doc)401 void MultiComparatorNonScoringCollector::collect(int32_t doc) {
402     ++totalHits;
403     if (queueFull) {
404         // Fastmatch: return if this hit is not competitive
405         for (int32_t i = 0; ; ++i) {
406             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
407             if (c < 0) {
408                 // Definitely not competitive.
409                 return;
410             } else if (c > 0) {
411                 // Definitely competitive.
412                 break;
413             } else if (i == comparators.size() - 1) {
414                 // Here c=0. If we're at the last comparator, this doc is not competitive, since docs are
415                 // visited in doc Id order, which means this doc cannot compete with any other document
416                 // in the queue.
417                 return;
418             }
419         }
420 
421         // This hit is competitive - replace bottom element in queue and adjustTop
422         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
423             (*cmp)->copy(bottom->slot, doc);
424         }
425 
426         updateBottom(doc);
427 
428         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
429             (*cmp)->setBottom(bottom->slot);
430         }
431     } else {
432         // Startup transient: queue hasn't gathered numHits yet
433         int32_t slot = totalHits - 1;
434         // Copy hit into queue
435         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
436             (*cmp)->copy(slot, doc);
437         }
438         add(slot, doc, std::numeric_limits<double>::quiet_NaN());
439         if (queueFull) {
440             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
441                 (*cmp)->setBottom(bottom->slot);
442             }
443         }
444     }
445 }
446 
setNextReader(const IndexReaderPtr & reader,int32_t docBase)447 void MultiComparatorNonScoringCollector::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
448     this->docBase = docBase;
449     for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
450         (*cmp)->setNextReader(reader, docBase);
451     }
452 }
453 
setScorer(const ScorerPtr & scorer)454 void MultiComparatorNonScoringCollector::setScorer(const ScorerPtr& scorer) {
455     // set the scorer on all comparators
456     for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
457         (*cmp)->setScorer(scorer);
458     }
459 }
460 
OutOfOrderMultiComparatorNonScoringCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)461 OutOfOrderMultiComparatorNonScoringCollector::OutOfOrderMultiComparatorNonScoringCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : MultiComparatorNonScoringCollector(queue, numHits, fillFields) {
462 }
463 
~OutOfOrderMultiComparatorNonScoringCollector()464 OutOfOrderMultiComparatorNonScoringCollector::~OutOfOrderMultiComparatorNonScoringCollector() {
465 }
466 
collect(int32_t doc)467 void OutOfOrderMultiComparatorNonScoringCollector::collect(int32_t doc) {
468     ++totalHits;
469     if (queueFull) {
470         // Fastmatch: return if this hit is not competitive
471         for (int32_t i = 0; ; ++i) {
472             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
473             if (c < 0) {
474                 // Definitely not competitive.
475                 return;
476             } else if (c > 0) {
477                 // Definitely competitive.
478                 break;
479             } else if (i == comparators.size() - 1) {
480                 // This is the equals case.
481                 if (doc + docBase > bottom->doc) {
482                     // Definitely not competitive
483                     return;
484                 }
485                 break;
486             }
487         }
488 
489         // This hit is competitive - replace bottom element in queue and adjustTop
490         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
491             (*cmp)->copy(bottom->slot, doc);
492         }
493 
494         updateBottom(doc);
495 
496         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
497             (*cmp)->setBottom(bottom->slot);
498         }
499     } else {
500         // Startup transient: queue hasn't gathered numHits yet
501         int32_t slot = totalHits - 1;
502         // Copy hit into queue
503         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
504             (*cmp)->copy(slot, doc);
505         }
506         add(slot, doc, std::numeric_limits<double>::quiet_NaN());
507         if (queueFull) {
508             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
509                 (*cmp)->setBottom(bottom->slot);
510             }
511         }
512     }
513 }
514 
acceptsDocsOutOfOrder()515 bool OutOfOrderMultiComparatorNonScoringCollector::acceptsDocsOutOfOrder() {
516     return true;
517 }
518 
MultiComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)519 MultiComparatorScoringMaxScoreCollector::MultiComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : MultiComparatorNonScoringCollector(queue, numHits, fillFields) {
520     // Must set maxScore to NEG_INF, or otherwise std::max always returns NaN.
521     this->maxScore = -std::numeric_limits<double>::infinity();
522 }
523 
~MultiComparatorScoringMaxScoreCollector()524 MultiComparatorScoringMaxScoreCollector::~MultiComparatorScoringMaxScoreCollector() {
525 }
526 
updateBottom(int32_t doc,double score)527 void MultiComparatorScoringMaxScoreCollector::updateBottom(int32_t doc, double score) {
528     bottom->doc = docBase + doc;
529     bottom->score = score;
530     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
531 }
532 
collect(int32_t doc)533 void MultiComparatorScoringMaxScoreCollector::collect(int32_t doc) {
534     double score = ScorerPtr(_scorer)->score();
535     if (score > maxScore) {
536         maxScore = score;
537     }
538     ++totalHits;
539     if (queueFull) {
540         // Fastmatch: return if this hit is not competitive
541         for (int32_t i = 0; ; ++i) {
542             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
543             if (c < 0) {
544                 // Definitely not competitive.
545                 return;
546             } else if (c > 0) {
547                 // Definitely competitive.
548                 break;
549             } else if (i == comparators.size() - 1) {
550                 // Here c=0. If we're at the last comparator, this doc is not competitive, since docs are
551                 // visited in doc Id order, which means this doc cannot compete with any other document
552                 // in the queue.
553                 return;
554             }
555         }
556 
557         // This hit is competitive - replace bottom element in queue and adjustTop
558         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
559             (*cmp)->copy(bottom->slot, doc);
560         }
561 
562         updateBottom(doc, score);
563 
564         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
565             (*cmp)->setBottom(bottom->slot);
566         }
567     } else {
568         // Startup transient: queue hasn't gathered numHits yet
569         int32_t slot = totalHits - 1;
570         // Copy hit into queue
571         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
572             (*cmp)->copy(slot, doc);
573         }
574         add(slot, doc, score);
575         if (queueFull) {
576             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
577                 (*cmp)->setBottom(bottom->slot);
578             }
579         }
580     }
581 }
582 
setScorer(const ScorerPtr & scorer)583 void MultiComparatorScoringMaxScoreCollector::setScorer(const ScorerPtr& scorer) {
584     this->_scorer = scorer;
585     MultiComparatorNonScoringCollector::setScorer(scorer);
586 }
587 
OutOfOrderMultiComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)588 OutOfOrderMultiComparatorScoringMaxScoreCollector::OutOfOrderMultiComparatorScoringMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : MultiComparatorScoringMaxScoreCollector(queue, numHits, fillFields) {
589 }
590 
~OutOfOrderMultiComparatorScoringMaxScoreCollector()591 OutOfOrderMultiComparatorScoringMaxScoreCollector::~OutOfOrderMultiComparatorScoringMaxScoreCollector() {
592 }
593 
collect(int32_t doc)594 void OutOfOrderMultiComparatorScoringMaxScoreCollector::collect(int32_t doc) {
595     double score = ScorerPtr(_scorer)->score();
596     if (score > maxScore) {
597         maxScore = score;
598     }
599     ++totalHits;
600     if (queueFull) {
601         // Fastmatch: return if this hit is not competitive
602         for (int32_t i = 0; ; ++i) {
603             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
604             if (c < 0) {
605                 // Definitely not competitive.
606                 return;
607             } else if (c > 0) {
608                 // Definitely competitive.
609                 break;
610             } else if (i == comparators.size() - 1) {
611                 // This is the equals case.
612                 if (doc + docBase > bottom->doc) {
613                     // Definitely not competitive
614                     return;
615                 }
616                 break;
617             }
618         }
619 
620         // This hit is competitive - replace bottom element in queue and adjustTop
621         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
622             (*cmp)->copy(bottom->slot, doc);
623         }
624 
625         updateBottom(doc, score);
626 
627         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
628             (*cmp)->setBottom(bottom->slot);
629         }
630     } else {
631         // Startup transient: queue hasn't gathered numHits yet
632         int32_t slot = totalHits - 1;
633         // Copy hit into queue
634         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
635             (*cmp)->copy(slot, doc);
636         }
637         add(slot, doc, score);
638         if (queueFull) {
639             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
640                 (*cmp)->setBottom(bottom->slot);
641             }
642         }
643     }
644 }
645 
acceptsDocsOutOfOrder()646 bool OutOfOrderMultiComparatorScoringMaxScoreCollector::acceptsDocsOutOfOrder() {
647     return true;
648 }
649 
MultiComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)650 MultiComparatorScoringNoMaxScoreCollector::MultiComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : MultiComparatorNonScoringCollector(queue, numHits, fillFields) {
651 }
652 
~MultiComparatorScoringNoMaxScoreCollector()653 MultiComparatorScoringNoMaxScoreCollector::~MultiComparatorScoringNoMaxScoreCollector() {
654 }
655 
updateBottom(int32_t doc,double score)656 void MultiComparatorScoringNoMaxScoreCollector::updateBottom(int32_t doc, double score) {
657     bottom->doc = docBase + doc;
658     bottom->score = score;
659     bottom = boost::static_pointer_cast<FieldValueHitQueueEntry>(pq->updateTop());
660 }
661 
collect(int32_t doc)662 void MultiComparatorScoringNoMaxScoreCollector::collect(int32_t doc) {
663     ++totalHits;
664     if (queueFull) {
665         // Fastmatch: return if this hit is not competitive
666         for (int32_t i = 0; ; ++i) {
667             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
668             if (c < 0) {
669                 // Definitely not competitive.
670                 return;
671             } else if (c > 0) {
672                 // Definitely competitive.
673                 break;
674             } else if (i == comparators.size() - 1) {
675                 // Here c=0. If we're at the last comparator, this doc is not competitive, since docs are
676                 // visited in doc Id order, which means this doc cannot compete with any other document
677                 // in the queue.
678                 return;
679             }
680         }
681 
682         // This hit is competitive - replace bottom element in queue and adjustTop
683         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
684             (*cmp)->copy(bottom->slot, doc);
685         }
686 
687         // Compute score only if it is competitive.
688         double score = ScorerPtr(_scorer)->score();
689         updateBottom(doc, score);
690 
691         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
692             (*cmp)->setBottom(bottom->slot);
693         }
694     } else {
695         // Startup transient: queue hasn't gathered numHits yet
696         int32_t slot = totalHits - 1;
697         // Copy hit into queue
698         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
699             (*cmp)->copy(slot, doc);
700         }
701 
702         // Compute score only if it is competitive.
703         double score = ScorerPtr(_scorer)->score();
704         add(slot, doc, score);
705         if (queueFull) {
706             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
707                 (*cmp)->setBottom(bottom->slot);
708             }
709         }
710     }
711 }
712 
setScorer(const ScorerPtr & scorer)713 void MultiComparatorScoringNoMaxScoreCollector::setScorer(const ScorerPtr& scorer) {
714     this->_scorer = scorer;
715     MultiComparatorNonScoringCollector::setScorer(scorer);
716 }
717 
OutOfOrderMultiComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr & queue,int32_t numHits,bool fillFields)718 OutOfOrderMultiComparatorScoringNoMaxScoreCollector::OutOfOrderMultiComparatorScoringNoMaxScoreCollector(const FieldValueHitQueuePtr& queue, int32_t numHits, bool fillFields) : MultiComparatorScoringNoMaxScoreCollector(queue, numHits, fillFields) {
719 }
720 
~OutOfOrderMultiComparatorScoringNoMaxScoreCollector()721 OutOfOrderMultiComparatorScoringNoMaxScoreCollector::~OutOfOrderMultiComparatorScoringNoMaxScoreCollector() {
722 }
723 
collect(int32_t doc)724 void OutOfOrderMultiComparatorScoringNoMaxScoreCollector::collect(int32_t doc) {
725     ++totalHits;
726     if (queueFull) {
727         // Fastmatch: return if this hit is not competitive
728         for (int32_t i = 0; ; ++i) {
729             int32_t c = reverseMul[i] * comparators[i]->compareBottom(doc);
730             if (c < 0) {
731                 // Definitely not competitive.
732                 return;
733             } else if (c > 0) {
734                 // Definitely competitive.
735                 break;
736             } else if (i == comparators.size() - 1) {
737                 // This is the equals case.
738                 if (doc + docBase > bottom->doc) {
739                     // Definitely not competitive
740                     return;
741                 }
742                 break;
743             }
744         }
745 
746         // This hit is competitive - replace bottom element in queue and adjustTop
747         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
748             (*cmp)->copy(bottom->slot, doc);
749         }
750 
751         // Compute score only if it is competitive.
752         double score = ScorerPtr(_scorer)->score();
753         updateBottom(doc, score);
754 
755         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
756             (*cmp)->setBottom(bottom->slot);
757         }
758     } else {
759         // Startup transient: queue hasn't gathered numHits yet
760         int32_t slot = totalHits - 1;
761         // Copy hit into queue
762         for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
763             (*cmp)->copy(slot, doc);
764         }
765 
766         // Compute score only if it is competitive.
767         double score = ScorerPtr(_scorer)->score();
768         add(slot, doc, score);
769         if (queueFull) {
770             for (Collection<FieldComparatorPtr>::iterator cmp = comparators.begin(); cmp != comparators.end(); ++cmp) {
771                 (*cmp)->setBottom(bottom->slot);
772             }
773         }
774     }
775 }
776 
setScorer(const ScorerPtr & scorer)777 void OutOfOrderMultiComparatorScoringNoMaxScoreCollector::setScorer(const ScorerPtr& scorer) {
778     this->_scorer = scorer;
779     MultiComparatorScoringNoMaxScoreCollector::setScorer(scorer);
780 }
781 
acceptsDocsOutOfOrder()782 bool OutOfOrderMultiComparatorScoringNoMaxScoreCollector::acceptsDocsOutOfOrder() {
783     return true;
784 }
785 
786 }
787