Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
TopScoreDocCollector.cs
Go to the documentation of this file.
1 /*
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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 using System;
19 
20 using IndexReader = Lucene.Net.Index.IndexReader;
21 
22 namespace Lucene.Net.Search
23 {
24 
25  /// <summary> A <see cref="Collector" /> implementation that collects the top-scoring hits,
26  /// returning them as a <see cref="TopDocs" />. This is used by <see cref="IndexSearcher" /> to
27  /// implement <see cref="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.
31  ///
32  /// <p/><b>NOTE</b>: The values <see cref="float.NaN" /> and
33  /// <see cref="float.NegativeInfinity" /> are not valid scores. This
34  /// collector will not properly collect hits with such
35  /// scores.
36  /// </summary>
37  public abstract class TopScoreDocCollector : TopDocsCollector<ScoreDoc>
38  {
39 
40  // Assumes docs are scored in order.
41  private class InOrderTopScoreDocCollector:TopScoreDocCollector
42  {
43  internal InOrderTopScoreDocCollector(int numHits):base(numHits)
44  {
45  }
46 
47  public override void Collect(int doc)
48  {
49  float score = scorer.Score();
50 
51  // This collector cannot handle these scores:
52  System.Diagnostics.Debug.Assert(score != float.NegativeInfinity);
53  System.Diagnostics.Debug.Assert(!float.IsNaN(score));
54 
55  internalTotalHits++;
56  if (score <= pqTop.Score)
57  {
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.
61  return ;
62  }
63  pqTop.Doc = doc + docBase;
64  pqTop.Score = score;
65  pqTop = pq.UpdateTop();
66  }
67 
68  public override bool AcceptsDocsOutOfOrder
69  {
70  get { return false; }
71  }
72  }
73 
74  // Assumes docs are scored out of order.
75  private class OutOfOrderTopScoreDocCollector:TopScoreDocCollector
76  {
77  internal OutOfOrderTopScoreDocCollector(int numHits):base(numHits)
78  {
79  }
80 
81  public override void Collect(int doc)
82  {
83  float score = scorer.Score();
84 
85  // This collector cannot handle NaN
86  System.Diagnostics.Debug.Assert(!float.IsNaN(score));
87 
88  internalTotalHits++;
89  doc += docBase;
90  if (score < pqTop.Score || (score == pqTop.Score && doc > pqTop.Doc))
91  {
92  return ;
93  }
94  pqTop.Doc = doc;
95  pqTop.Score = score;
96  pqTop = pq.UpdateTop();
97  }
98 
99  public override bool AcceptsDocsOutOfOrder
100  {
101  get { return true; }
102  }
103  }
104 
105  /// <summary> Creates a new <see cref="TopScoreDocCollector" /> given the number of hits to
106  /// collect and whether documents are scored in order by the input
107  /// <see cref="Scorer" /> to <see cref="SetScorer(Scorer)" />.
108  ///
109  /// <p/><b>NOTE</b>: The instances returned by this method
110  /// pre-allocate a full array of length
111  /// <c>numHits</c>, and fill the array with sentinel
112  /// objects.
113  /// </summary>
114  public static TopScoreDocCollector Create(int numHits, bool docsScoredInOrder)
115  {
116 
117  if (docsScoredInOrder)
118  {
119  return new InOrderTopScoreDocCollector(numHits);
120  }
121  else
122  {
123  return new OutOfOrderTopScoreDocCollector(numHits);
124  }
125  }
126 
127  internal ScoreDoc pqTop;
128  internal int docBase = 0;
129  internal Scorer scorer;
130 
131  // prevents instantiation
132  private TopScoreDocCollector(int numHits):base(new HitQueue(numHits, true))
133  {
134  // HitQueue implements getSentinelObject to return a ScoreDoc, so we know
135  // that at this point top() is already initialized.
136  pqTop = pq.Top();
137  }
138 
139  public /*protected internal*/ override TopDocs NewTopDocs(ScoreDoc[] results, int start)
140  {
141  if (results == null)
142  {
143  return EMPTY_TOPDOCS;
144  }
145 
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;
151  if (start == 0)
152  {
153  maxScore = results[0].Score;
154  }
155  else
156  {
157  for (int i = pq.Size(); i > 1; i--)
158  {
159  pq.Pop();
160  }
161  maxScore = pq.Pop().Score;
162  }
163 
164  return new TopDocs(internalTotalHits, results, maxScore);
165  }
166 
167  public override void SetNextReader(IndexReader reader, int base_Renamed)
168  {
169  docBase = base_Renamed;
170  }
171 
172  public override void SetScorer(Scorer scorer)
173  {
174  this.scorer = scorer;
175  }
176  }
177 }