2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 using IndexReader = Mono.Lucene.Net.Index.IndexReader;
22 namespace Mono.Lucene.Net.Search
25 /// <summary> A {@link Collector} implementation that collects the top-scoring hits,
26 /// returning them as a {@link TopDocs}. This is used by {@link IndexSearcher} to
27 /// implement {@link TopDocs}-based search. Hits are sorted by score descending
28 /// and then (when the scores are tied) docID ascending. When you create an
29 /// instance of this collector you should know in advance whether documents are
30 /// going to be collected in doc Id order or not.
32 /// <p/><b>NOTE</b>: The values {@link Float#NaN} and
33 /// {Float#NEGATIVE_INFINITY} are not valid scores. This
34 /// collector will not properly collect hits with such
37 public abstract class TopScoreDocCollector:TopDocsCollector
40 // Assumes docs are scored in order.
41 private class InOrderTopScoreDocCollector:TopScoreDocCollector
43 internal InOrderTopScoreDocCollector(int numHits):base(numHits)
47 public override void Collect(int doc)
49 float score = scorer.Score();
51 // This collector cannot handle these scores:
52 System.Diagnostics.Debug.Assert(score != float.NegativeInfinity);
53 System.Diagnostics.Debug.Assert(!float.IsNaN(score));
56 if (score <= pqTop.score)
58 // Since docs are returned in-order (i.e., increasing doc Id), a document
59 // with equal score to pqTop.score cannot compete since HitQueue favors
60 // documents with lower doc Ids. Therefore reject those docs too.
63 pqTop.doc = doc + docBase;
65 pqTop = (ScoreDoc) pq.UpdateTop();
68 public override bool AcceptsDocsOutOfOrder()
74 // Assumes docs are scored out of order.
75 private class OutOfOrderTopScoreDocCollector:TopScoreDocCollector
77 internal OutOfOrderTopScoreDocCollector(int numHits):base(numHits)
81 public override void Collect(int doc)
83 float score = scorer.Score();
85 // This collector cannot handle NaN
86 System.Diagnostics.Debug.Assert(!float.IsNaN(score));
90 if (score < pqTop.score || (score == pqTop.score && doc > pqTop.doc))
96 pqTop = (ScoreDoc) pq.UpdateTop();
99 public override bool AcceptsDocsOutOfOrder()
105 /// <summary> Creates a new {@link TopScoreDocCollector} given the number of hits to
106 /// collect and whether documents are scored in order by the input
107 /// {@link Scorer} to {@link #SetScorer(Scorer)}.
109 /// <p/><b>NOTE</b>: The instances returned by this method
110 /// pre-allocate a full array of length
111 /// <code>numHits</code>, and fill the array with sentinel
114 public static TopScoreDocCollector create(int numHits, bool docsScoredInOrder)
117 if (docsScoredInOrder)
119 return new InOrderTopScoreDocCollector(numHits);
123 return new OutOfOrderTopScoreDocCollector(numHits);
127 internal ScoreDoc pqTop;
128 internal int docBase = 0;
129 internal Scorer scorer;
131 // prevents instantiation
132 private TopScoreDocCollector(int numHits):base(new HitQueue(numHits, true))
134 // HitQueue implements getSentinelObject to return a ScoreDoc, so we know
135 // that at this point top() is already initialized.
136 pqTop = (ScoreDoc) pq.Top();
139 public /*protected internal*/ override TopDocs NewTopDocs(ScoreDoc[] results, int start)
143 return EMPTY_TOPDOCS;
146 // We need to compute maxScore in order to set it in TopDocs. If start == 0,
147 // it means the largest element is already in results, use its score as
148 // maxScore. Otherwise pop everything else, until the largest element is
149 // extracted and use its score as maxScore.
150 float maxScore = System.Single.NaN;
153 maxScore = results[0].score;
157 for (int i = pq.Size(); i > 1; i--)
161 maxScore = ((ScoreDoc) pq.Pop()).score;
164 return new TopDocs(totalHits, results, maxScore);
167 public override void SetNextReader(IndexReader reader, int base_Renamed)
169 docBase = base_Renamed;
172 public override void SetScorer(Scorer scorer)
174 this.scorer = scorer;