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