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
DisjunctionSumScorer.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 ScorerDocQueue = Lucene.Net.Util.ScorerDocQueue;
21 
22 namespace Lucene.Net.Search
23 {
24 
25  /// <summary>A Scorer for OR like queries, counterpart of <c>ConjunctionScorer</c>.
26  /// This Scorer implements <see cref="DocIdSetIterator.Advance(int)" /> and uses skipTo() on the given Scorers.
27  /// </summary>
29  {
30  /// <summary>The number of subscorers. </summary>
31  private int nrScorers;
32 
33  /// <summary>The subscorers. </summary>
34  protected internal System.Collections.Generic.IList<Scorer> subScorers;
35 
36  /// <summary>The minimum number of scorers that should match. </summary>
37  private int minimumNrMatchers;
38 
39  /// <summary>The scorerDocQueue contains all subscorers ordered by their current doc(),
40  /// with the minimum at the top.
41  /// <br/>The scorerDocQueue is initialized the first time next() or skipTo() is called.
42  /// <br/>An exhausted scorer is immediately removed from the scorerDocQueue.
43  /// <br/>If less than the minimumNrMatchers scorers
44  /// remain in the scorerDocQueue next() and skipTo() return false.
45  /// <p/>
46  /// After each to call to next() or skipTo()
47  /// <c>currentSumScore</c> is the total score of the current matching doc,
48  /// <c>nrMatchers</c> is the number of matching scorers,
49  /// and all scorers are after the matching doc, or are exhausted.
50  /// </summary>
51  private ScorerDocQueue scorerDocQueue;
52 
53  /// <summary>The document number of the current match. </summary>
54  private int currentDoc = - 1;
55 
56  /// <summary>The number of subscorers that provide the current match. </summary>
57  protected internal int nrMatchers = - 1;
58 
59  private float currentScore = System.Single.NaN;
60 
61  /// <summary>Construct a <c>DisjunctionScorer</c>.</summary>
62  /// <param name="subScorers">A collection of at least two subscorers.
63  /// </param>
64  /// <param name="minimumNrMatchers">The positive minimum number of subscorers that should
65  /// match to match this query.
66  /// <br/>When <c>minimumNrMatchers</c> is bigger than
67  /// the number of <c>subScorers</c>,
68  /// no matches will be produced.
69  /// <br/>When minimumNrMatchers equals the number of subScorers,
70  /// it more efficient to use <c>ConjunctionScorer</c>.
71  /// </param>
72  public DisjunctionSumScorer(System.Collections.Generic.IList<Scorer> subScorers, int minimumNrMatchers):base(null)
73  {
74 
75  nrScorers = subScorers.Count;
76 
77  if (minimumNrMatchers <= 0)
78  {
79  throw new System.ArgumentException("Minimum nr of matchers must be positive");
80  }
81  if (nrScorers <= 1)
82  {
83  throw new System.ArgumentException("There must be at least 2 subScorers");
84  }
85 
86  this.minimumNrMatchers = minimumNrMatchers;
87  this.subScorers = subScorers;
88 
89  InitScorerDocQueue();
90  }
91 
92  /// <summary>Construct a <c>DisjunctionScorer</c>, using one as the minimum number
93  /// of matching subscorers.
94  /// </summary>
95  public DisjunctionSumScorer(System.Collections.Generic.IList<Scorer> subScorers)
96  : this(subScorers, 1)
97  {
98  }
99 
100  /// <summary>Called the first time next() or skipTo() is called to
101  /// initialize <c>scorerDocQueue</c>.
102  /// </summary>
103  private void InitScorerDocQueue()
104  {
105  scorerDocQueue = new ScorerDocQueue(nrScorers);
106  foreach(Scorer se in subScorers)
107  {
108  if (se.NextDoc() != NO_MORE_DOCS)
109  {
110  // doc() method will be used in scorerDocQueue.
111  scorerDocQueue.Insert(se);
112  }
113  }
114  }
115 
116  /// <summary>Scores and collects all matching documents.</summary>
117  /// <param name="collector">The collector to which all matching documents are passed through.</param>
118  public override void Score(Collector collector)
119  {
120  collector.SetScorer(this);
121  while (NextDoc() != NO_MORE_DOCS)
122  {
123  collector.Collect(currentDoc);
124  }
125  }
126 
127  /// <summary>Expert: Collects matching documents in a range. Hook for optimization.
128  /// Note that <see cref="NextDoc()" /> must be called once before this method is called
129  /// for the first time.
130  /// </summary>
131  /// <param name="collector">The collector to which all matching documents are passed through.
132  /// </param>
133  /// <param name="max">Do not score documents past this.
134  /// </param>
135  /// <param name="firstDocID"></param>
136  /// <returns> true if more matching documents may remain.
137  /// </returns>
138  public /*protected internal*/ override bool Score(Collector collector, int max, int firstDocID)
139  {
140  // firstDocID is ignored since nextDoc() sets 'currentDoc'
141  collector.SetScorer(this);
142  while (currentDoc < max)
143  {
144  collector.Collect(currentDoc);
145  if (NextDoc() == NO_MORE_DOCS)
146  {
147  return false;
148  }
149  }
150  return true;
151  }
152 
153  public override int NextDoc()
154  {
155  if (scorerDocQueue.Size() < minimumNrMatchers || !AdvanceAfterCurrent())
156  {
157  currentDoc = NO_MORE_DOCS;
158  }
159  return currentDoc;
160  }
161 
162  /// <summary>Advance all subscorers after the current document determined by the
163  /// top of the <c>scorerDocQueue</c>.
164  /// Repeat until at least the minimum number of subscorers match on the same
165  /// document and all subscorers are after that document or are exhausted.
166  /// <br/>On entry the <c>scorerDocQueue</c> has at least <c>minimumNrMatchers</c>
167  /// available. At least the scorer with the minimum document number will be advanced.
168  /// </summary>
169  /// <returns> true iff there is a match.
170  /// <br/>In case there is a match, <c>currentDoc</c>, <c>currentSumScore</c>,
171  /// and <c>nrMatchers</c> describe the match.
172  ///
173  /// TODO: Investigate whether it is possible to use skipTo() when
174  /// the minimum number of matchers is bigger than one, ie. try and use the
175  /// character of ConjunctionScorer for the minimum number of matchers.
176  /// Also delay calling score() on the sub scorers until the minimum number of
177  /// matchers is reached.
178  /// <br/>For this, a Scorer array with minimumNrMatchers elements might
179  /// hold Scorers at currentDoc that are temporarily popped from scorerQueue.
180  /// </returns>
181  protected internal virtual bool AdvanceAfterCurrent()
182  {
183  do
184  {
185  // repeat until minimum nr of matchers
186  currentDoc = scorerDocQueue.TopDoc();
187  currentScore = scorerDocQueue.TopScore();
188  nrMatchers = 1;
189  do
190  {
191  // Until all subscorers are after currentDoc
192  if (!scorerDocQueue.TopNextAndAdjustElsePop())
193  {
194  if (scorerDocQueue.Size() == 0)
195  {
196  break; // nothing more to advance, check for last match.
197  }
198  }
199  if (scorerDocQueue.TopDoc() != currentDoc)
200  {
201  break; // All remaining subscorers are after currentDoc.
202  }
203  currentScore += scorerDocQueue.TopScore();
204  nrMatchers++;
205  }
206  while (true);
207 
208  if (nrMatchers >= minimumNrMatchers)
209  {
210  return true;
211  }
212  else if (scorerDocQueue.Size() < minimumNrMatchers)
213  {
214  return false;
215  }
216  }
217  while (true);
218  }
219 
220  /// <summary>Returns the score of the current document matching the query.
221  /// Initially invalid, until <see cref="NextDoc()" /> is called the first time.
222  /// </summary>
223  public override float Score()
224  {
225  return currentScore;
226  }
227 
228  public override int DocID()
229  {
230  return currentDoc;
231  }
232 
233  /// <summary>Returns the number of subscorers matching the current document.
234  /// Initially invalid, until <see cref="NextDoc()" /> is called the first time.
235  /// </summary>
236  public virtual int NrMatchers()
237  {
238  return nrMatchers;
239  }
240 
241  /// <summary> Advances to the first match beyond the current whose document number is
242  /// greater than or equal to a given target. <br/>
243  /// The implementation uses the skipTo() method on the subscorers.
244  ///
245  /// </summary>
246  /// <param name="target">The target document number.
247  /// </param>
248  /// <returns> the document whose number is greater than or equal to the given
249  /// target, or -1 if none exist.
250  /// </returns>
251  public override int Advance(int target)
252  {
253  if (scorerDocQueue.Size() < minimumNrMatchers)
254  {
255  return currentDoc = NO_MORE_DOCS;
256  }
257  if (target <= currentDoc)
258  {
259  return currentDoc;
260  }
261  do
262  {
263  if (scorerDocQueue.TopDoc() >= target)
264  {
265  return AdvanceAfterCurrent()?currentDoc:(currentDoc = NO_MORE_DOCS);
266  }
267  else if (!scorerDocQueue.TopSkipToAndAdjustElsePop(target))
268  {
269  if (scorerDocQueue.Size() < minimumNrMatchers)
270  {
271  return currentDoc = NO_MORE_DOCS;
272  }
273  }
274  }
275  while (true);
276  }
277  }
278 }