cvsimport
[beagle.git] / beagled / Lucene.Net / Search / DisjunctionSumScorer.cs
blob3aab5c3b2ac54c2dbd17d71221ec5dcf7b467e9f
1 /*
2 * Copyright 2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 using System;
18 using PriorityQueue = Lucene.Net.Util.PriorityQueue;
20 namespace Lucene.Net.Search
23 /// <summary>A Scorer for OR like queries, counterpart of Lucene's <code>ConjunctionScorer</code>.
24 /// This Scorer implements {@link Scorer#SkipTo(int)} and uses skipTo() on the given Scorers.
25 /// </summary>
26 public class DisjunctionSumScorer : Scorer
28 /// <summary>The number of subscorers. </summary>
29 private int nrScorers;
31 /// <summary>The subscorers. </summary>
32 protected internal System.Collections.IList subScorers;
34 /// <summary>The minimum number of scorers that should match. </summary>
35 private int minimumNrMatchers;
37 /// <summary>The scorerQueue contains all subscorers ordered by their current doc(),
38 /// with the minimum at the top.
39 /// <br>The scorerQueue is initialized the first time next() or skipTo() is called.
40 /// <br>An exhausted scorer is immediately removed from the scorerQueue.
41 /// <br>If less than the minimumNrMatchers scorers
42 /// remain in the scorerQueue next() and skipTo() return false.
43 /// <p>
44 /// After each to call to next() or skipTo()
45 /// <code>currentSumScore</code> is the total score of the current matching doc,
46 /// <code>nrMatchers</code> is the number of matching scorers,
47 /// and all scorers are after the matching doc, or are exhausted.
48 /// </summary>
49 private ScorerQueue scorerQueue = null;
51 /// <summary>The document number of the current match. </summary>
52 private int currentDoc = - 1;
54 /// <summary>The number of subscorers that provide the current match. </summary>
55 protected internal int nrMatchers = - 1;
57 private float currentScore = System.Single.NaN;
59 /// <summary>Construct a <code>DisjunctionScorer</code>.</summary>
60 /// <param name="subScorers">A collection of at least two subscorers.
61 /// </param>
62 /// <param name="minimumNrMatchers">The positive minimum number of subscorers that should
63 /// match to match this query.
64 /// <br>When <code>minimumNrMatchers</code> is bigger than
65 /// the number of <code>subScorers</code>,
66 /// no matches will be produced.
67 /// <br>When minimumNrMatchers equals the number of subScorers,
68 /// it more efficient to use <code>ConjunctionScorer</code>.
69 /// </param>
70 public DisjunctionSumScorer(System.Collections.IList subScorers, int minimumNrMatchers) : base(null)
73 nrScorers = subScorers.Count;
75 if (minimumNrMatchers <= 0)
77 throw new System.ArgumentException("Minimum nr of matchers must be positive");
79 if (nrScorers <= 1)
81 throw new System.ArgumentException("There must be at least 2 subScorers");
84 this.minimumNrMatchers = minimumNrMatchers;
85 this.subScorers = subScorers;
88 /// <summary>Construct a <code>DisjunctionScorer</code>, using one as the minimum number
89 /// of matching subscorers.
90 /// </summary>
91 public DisjunctionSumScorer(System.Collections.IList subScorers) : this(subScorers, 1)
95 /// <summary>Called the first time next() or skipTo() is called to
96 /// initialize <code>scorerQueue</code>.
97 /// </summary>
98 private void InitScorerQueue()
100 System.Collections.IEnumerator si = subScorers.GetEnumerator();
101 scorerQueue = new ScorerQueue(this, nrScorers);
102 while (si.MoveNext())
104 Scorer se = (Scorer) si.Current;
105 if (se.Next())
107 // doc() method will be used in scorerQueue.
108 scorerQueue.Insert(se);
113 /// <summary>A <code>PriorityQueue</code> that orders by {@link Scorer#Doc()}. </summary>
114 private class ScorerQueue : PriorityQueue
116 private void InitBlock(DisjunctionSumScorer enclosingInstance)
118 this.enclosingInstance = enclosingInstance;
120 private DisjunctionSumScorer enclosingInstance;
121 public DisjunctionSumScorer Enclosing_Instance
125 return enclosingInstance;
129 internal ScorerQueue(DisjunctionSumScorer enclosingInstance, int size)
131 InitBlock(enclosingInstance);
132 Initialize(size);
135 public override bool LessThan(System.Object o1, System.Object o2)
137 return ((Scorer) o1).Doc() < ((Scorer) o2).Doc();
141 public override bool Next()
143 if (scorerQueue == null)
145 InitScorerQueue();
147 if (scorerQueue.Size() < minimumNrMatchers)
149 return false;
151 else
153 return AdvanceAfterCurrent();
158 /// <summary>Advance all subscorers after the current document determined by the
159 /// top of the <code>scorerQueue</code>.
160 /// Repeat until at least the minimum number of subscorers match on the same
161 /// document and all subscorers are after that document or are exhausted.
162 /// <br>On entry the <code>scorerQueue</code> has at least <code>minimumNrMatchers</code>
163 /// available. At least the scorer with the minimum document number will be advanced.
164 /// </summary>
165 /// <returns> true iff there is a match.
166 /// <br>In case there is a match, </code>currentDoc</code>, </code>currentSumScore</code>,
167 /// and </code>nrMatchers</code> describe the match.
168 ///
169 /// </returns>
170 /// <todo> Investigate whether it is possible to use skipTo() when </todo>
171 /// <summary> the minimum number of matchers is bigger than one, ie. try and use the
172 /// character of ConjunctionScorer for the minimum number of matchers.
173 /// </summary>
174 protected internal virtual bool AdvanceAfterCurrent()
178 // repeat until minimum nr of matchers
179 Scorer top = (Scorer) scorerQueue.Top();
180 currentDoc = top.Doc();
181 currentScore = top.Score();
182 nrMatchers = 1;
185 // Until all subscorers are after currentDoc
186 if (top.Next())
188 scorerQueue.AdjustTop();
190 else
192 scorerQueue.Pop();
193 if (scorerQueue.Size() < (minimumNrMatchers - nrMatchers))
195 // Not enough subscorers left for a match on this document,
196 // and also no more chance of any further match.
197 return false;
199 if (scorerQueue.Size() == 0)
201 break; // nothing more to advance, check for last match.
204 top = (Scorer) scorerQueue.Top();
205 if (top.Doc() != currentDoc)
207 break; // All remaining subscorers are after currentDoc.
209 else
211 currentScore += top.Score();
212 nrMatchers++;
215 while (true);
217 if (nrMatchers >= minimumNrMatchers)
219 return true;
221 else if (scorerQueue.Size() < minimumNrMatchers)
223 return false;
226 while (true);
229 /// <summary>Returns the score of the current document matching the query.
230 /// Initially invalid, until {@link #Next()} is called the first time.
231 /// </summary>
232 public override float Score()
234 return currentScore;
237 public override int Doc()
239 return currentDoc;
242 /// <summary>Returns the number of subscorers matching the current document.
243 /// Initially invalid, until {@link #Next()} is called the first time.
244 /// </summary>
245 public virtual int NrMatchers()
247 return nrMatchers;
250 /// <summary>Skips to the first match beyond the current whose document number is
251 /// greater than or equal to a given target.
252 /// <br>When this method is used the {@link #Explain(int)} method should not be used.
253 /// <br>The implementation uses the skipTo() method on the subscorers.
254 /// </summary>
255 /// <param name="target">The target document number.
256 /// </param>
257 /// <returns> true iff there is such a match.
258 /// </returns>
259 public override bool SkipTo(int target)
261 if (scorerQueue == null)
263 InitScorerQueue();
265 if (scorerQueue.Size() < minimumNrMatchers)
267 return false;
269 if (target <= currentDoc)
271 target = currentDoc + 1;
275 Scorer top = (Scorer) scorerQueue.Top();
276 if (top.Doc() >= target)
278 return AdvanceAfterCurrent();
280 else if (top.SkipTo(target))
282 scorerQueue.AdjustTop();
284 else
286 scorerQueue.Pop();
287 if (scorerQueue.Size() < minimumNrMatchers)
289 return false;
293 while (true);
296 /// <summary>Gives and explanation for the score of a given document.</summary>
297 /// <todo> Show the resulting score. See BooleanScorer.explain() on how to do this. </todo>
298 public override Explanation Explain(int doc)
300 Explanation res = new Explanation();
301 res.SetDescription("At least " + minimumNrMatchers + " of");
302 System.Collections.IEnumerator ssi = subScorers.GetEnumerator();
303 while (ssi.MoveNext())
305 res.AddDetail(((Scorer) ssi.Current).Explain(doc));
307 return res;