Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Search / TopScoreDocCollector.cs
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 = Mono.Lucene.Net.Index.IndexReader;
21
22 namespace Mono.Lucene.Net.Search
23 {
24         
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.
31         /// 
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
35     /// scores.
36         /// </summary>
37         public abstract class TopScoreDocCollector:TopDocsCollector
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                                 totalHits++;
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 = (ScoreDoc) pq.UpdateTop();
66                         }
67                         
68                         public override bool AcceptsDocsOutOfOrder()
69                         {
70                                 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                                 totalHits++;
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 = (ScoreDoc) pq.UpdateTop();
97                         }
98                         
99                         public override bool AcceptsDocsOutOfOrder()
100                         {
101                                 return true;
102                         }
103                 }
104                 
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)}.
108                 /// 
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
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 = (ScoreDoc) 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 = ((ScoreDoc) pq.Pop()).score;
162                         }
163                         
164                         return new TopDocs(totalHits, 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 }