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 "TopScoreDocCollector.h"
9 #include "_TopScoreDocCollector.h"
10 #include "HitQueue.h"
11 #include "ScoreDoc.h"
12 #include "Scorer.h"
13 #include "TopDocs.h"
14 #include "MiscUtils.h"
15
16 namespace Lucene {
17
TopScoreDocCollector(int32_t numHits)18 TopScoreDocCollector::TopScoreDocCollector(int32_t numHits) : TopDocsCollector(newLucene<HitQueue>(numHits, true)) {
19 // HitQueue implements getSentinelObject to return a ScoreDoc, so we know that at this point top()
20 // is already initialized.
21 pqTop = pq->top();
22 docBase = 0;
23 }
24
~TopScoreDocCollector()25 TopScoreDocCollector::~TopScoreDocCollector() {
26 }
27
create(int32_t numHits,bool docsScoredInOrder)28 TopScoreDocCollectorPtr TopScoreDocCollector::create(int32_t numHits, bool docsScoredInOrder) {
29 if (docsScoredInOrder) {
30 return newLucene<InOrderTopScoreDocCollector>(numHits);
31 } else {
32 return newLucene<OutOfOrderTopScoreDocCollector>(numHits);
33 }
34 }
35
newTopDocs(Collection<ScoreDocPtr> results,int32_t start)36 TopDocsPtr TopScoreDocCollector::newTopDocs(Collection<ScoreDocPtr> results, int32_t start) {
37 if (!results) {
38 return EMPTY_TOPDOCS();
39 }
40
41 // We need to compute maxScore in order to set it in TopDocs. If start == 0, it means the largest element
42 // is already in results, use its score as maxScore. Otherwise pop everything else, until the largest
43 // element is extracted and use its score as maxScore.
44 double maxScore = std::numeric_limits<double>::quiet_NaN();
45 if (start == 0) {
46 maxScore = results[0]->score;
47 } else {
48 for (int32_t i = pq->size(); i > 1; --i) {
49 pq->pop();
50 }
51 maxScore = pq->pop()->score;
52 }
53
54 return newLucene<TopDocs>(totalHits, results, maxScore);
55 }
56
setNextReader(const IndexReaderPtr & reader,int32_t docBase)57 void TopScoreDocCollector::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
58 this->docBase = docBase;
59 }
60
setScorer(const ScorerPtr & scorer)61 void TopScoreDocCollector::setScorer(const ScorerPtr& scorer) {
62 this->_scorer = scorer;
63 }
64
InOrderTopScoreDocCollector(int32_t numHits)65 InOrderTopScoreDocCollector::InOrderTopScoreDocCollector(int32_t numHits) : TopScoreDocCollector(numHits) {
66 }
67
~InOrderTopScoreDocCollector()68 InOrderTopScoreDocCollector::~InOrderTopScoreDocCollector() {
69 }
70
collect(int32_t doc)71 void InOrderTopScoreDocCollector::collect(int32_t doc) {
72 double score = ScorerPtr(_scorer)->score();
73
74 // This collector cannot handle these scores
75 BOOST_ASSERT(score != -std::numeric_limits<double>::infinity());
76 BOOST_ASSERT(!MiscUtils::isNaN(score));
77
78 ++totalHits;
79 if (score <= pqTop->score) {
80 // Since docs are returned in-order (ie., increasing doc Id), a document with equal score to
81 // pqTop.score cannot compete since HitQueue favours documents with lower doc Ids. Therefore
82 // reject those docs too.
83 return;
84 }
85 pqTop->doc = doc + docBase;
86 pqTop->score = score;
87 pqTop = pq->updateTop();
88 }
89
acceptsDocsOutOfOrder()90 bool InOrderTopScoreDocCollector::acceptsDocsOutOfOrder() {
91 return false;
92 }
93
OutOfOrderTopScoreDocCollector(int32_t numHits)94 OutOfOrderTopScoreDocCollector::OutOfOrderTopScoreDocCollector(int32_t numHits) : TopScoreDocCollector(numHits) {
95 }
96
~OutOfOrderTopScoreDocCollector()97 OutOfOrderTopScoreDocCollector::~OutOfOrderTopScoreDocCollector() {
98 }
99
collect(int32_t doc)100 void OutOfOrderTopScoreDocCollector::collect(int32_t doc) {
101 double score = ScorerPtr(_scorer)->score();
102
103 // This collector cannot handle NaN
104 BOOST_ASSERT(!MiscUtils::isNaN(score));
105
106 ++totalHits;
107 doc += docBase;
108 if (score < pqTop->score || (score == pqTop->score && doc > pqTop->doc)) {
109 return;
110 }
111 pqTop->doc = doc;
112 pqTop->score = score;
113 pqTop = pq->updateTop();
114 }
115
acceptsDocsOutOfOrder()116 bool OutOfOrderTopScoreDocCollector::acceptsDocsOutOfOrder() {
117 return true;
118 }
119
120 }
121