QueryResponses.cs, DumpIndex.cs, IQueryResult.cs, QueryExecutor.cs, QueryResult.cs...
[beagle.git] / beagled / Lucene.Net / Search / BooleanScorer2.cs
blobb2bcbd0a9920d1c832008eb221ff7468a1e09340
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;
19 namespace Lucene.Net.Search
22 /// <summary>An alternative to BooleanScorer.
23 /// <br>Uses ConjunctionScorer, DisjunctionScorer, ReqOptScorer and ReqExclScorer.
24 /// <br>Implements skipTo(), and has no limitations on the numbers of added scorers.
25 /// </summary>
26 class BooleanScorer2 : Scorer
28 private class AnonymousClassDisjunctionSumScorer : DisjunctionSumScorer
30 private void InitBlock(BooleanScorer2 enclosingInstance)
32 this.enclosingInstance = enclosingInstance;
34 private BooleanScorer2 enclosingInstance;
35 public BooleanScorer2 Enclosing_Instance
37 get
39 return enclosingInstance;
43 internal AnonymousClassDisjunctionSumScorer(BooleanScorer2 enclosingInstance, System.Collections.IList Param1, int Param2):base(Param1, Param2)
45 InitBlock(enclosingInstance);
47 private int lastScoredDoc = - 1;
48 public override float Score()
50 if (Doc() > lastScoredDoc)
52 lastScoredDoc = Doc();
53 Enclosing_Instance.coordinator.nrMatchers += base.nrMatchers;
55 return base.Score();
59 private class AnonymousClassConjunctionScorer : ConjunctionScorer
61 private void InitBlock(int requiredNrMatchers, BooleanScorer2 enclosingInstance)
63 this.requiredNrMatchers = requiredNrMatchers;
64 this.enclosingInstance = enclosingInstance;
66 private int requiredNrMatchers;
67 private BooleanScorer2 enclosingInstance;
69 public BooleanScorer2 Enclosing_Instance
71 get
73 return enclosingInstance;
77 internal AnonymousClassConjunctionScorer(int requiredNrMatchers, BooleanScorer2 enclosingInstance, Lucene.Net.Search.Similarity Param1):base(Param1)
79 InitBlock(requiredNrMatchers, enclosingInstance);
81 private int lastScoredDoc = - 1;
83 public override float Score()
85 if (Doc() > lastScoredDoc)
87 lastScoredDoc = Doc();
88 Enclosing_Instance.coordinator.nrMatchers += requiredNrMatchers;
90 // All scorers match, so defaultSimilarity super.score() always has 1 as
91 // the coordination factor.
92 // Therefore the sum of the scores of the requiredScorers
93 // is used as score.
94 return base.Score();
97 private System.Collections.ArrayList requiredScorers = new System.Collections.ArrayList();
98 private System.Collections.ArrayList optionalScorers = new System.Collections.ArrayList();
99 private System.Collections.ArrayList prohibitedScorers = new System.Collections.ArrayList();
102 private class Coordinator
104 public Coordinator(BooleanScorer2 enclosingInstance)
106 InitBlock(enclosingInstance);
108 private void InitBlock(BooleanScorer2 enclosingInstance)
110 this.enclosingInstance = enclosingInstance;
112 private BooleanScorer2 enclosingInstance;
113 public BooleanScorer2 Enclosing_Instance
117 return enclosingInstance;
121 internal int maxCoord = 0; // to be increased for each non prohibited scorer
123 private float[] coordFactors = null;
125 internal virtual void Init()
127 // use after all scorers have been added.
128 coordFactors = new float[maxCoord + 1];
129 Similarity sim = Enclosing_Instance.GetSimilarity();
130 for (int i = 0; i <= maxCoord; i++)
132 coordFactors[i] = sim.Coord(i, maxCoord);
136 internal int nrMatchers; // to be increased by score() of match counting scorers.
138 internal virtual void InitDoc()
140 nrMatchers = 0;
143 internal virtual float CoordFactor()
145 return coordFactors[nrMatchers];
149 private Coordinator coordinator;
151 /// <summary>The scorer to which all scoring will be delegated,
152 /// except for computing and using the coordination factor.
153 /// </summary>
154 private Scorer countingSumScorer = null;
156 /// <summary>The number of optionalScorers that need to match (if there are any) </summary>
157 private int minNrShouldMatch;
159 /// <summary>Create a BooleanScorer2.</summary>
160 /// <param name="similarity">The similarity to be used.
161 /// </param>
162 /// <param name="minNrShouldMatch">The minimum number of optional added scorers
163 /// that should match during the search.
164 /// In case no required scorers are added,
165 /// at least one of the optional scorers will have to
166 /// match during the search.
167 /// </param>
168 public BooleanScorer2(Similarity similarity, int minNrShouldMatch):base(similarity)
170 if (minNrShouldMatch < 0)
172 throw new System.ArgumentException("Minimum number of optional scorers should not be negative");
174 coordinator = new Coordinator(this);
175 this.minNrShouldMatch = minNrShouldMatch;
178 /// <summary>Create a BooleanScorer2.
179 /// In no required scorers are added,
180 /// at least one of the optional scorers will have to match during the search.
181 /// </summary>
182 /// <param name="similarity">The similarity to be used.
183 /// </param>
184 public BooleanScorer2(Similarity similarity) : this(similarity, 0)
188 public virtual void Add(Scorer scorer, bool required, bool prohibited)
190 if (!prohibited)
192 coordinator.maxCoord++;
195 if (required)
197 if (prohibited)
199 throw new System.ArgumentException("scorer cannot be required and prohibited");
201 requiredScorers.Add(scorer);
203 else if (prohibited)
205 prohibitedScorers.Add(scorer);
207 else
209 optionalScorers.Add(scorer);
213 /// <summary>Initialize the match counting scorer that sums all the
214 /// scores. <p>
215 /// When "counting" is used in a name it means counting the number
216 /// of matching scorers.<br>
217 /// When "sum" is used in a name it means score value summing
218 /// over the matching scorers
219 /// </summary>
220 private void InitCountingSumScorer()
222 coordinator.Init();
223 countingSumScorer = MakeCountingSumScorer();
226 /// <summary>Count a scorer as a single match. </summary>
227 private class SingleMatchScorer : Scorer
229 private void InitBlock(BooleanScorer2 enclosingInstance)
231 this.enclosingInstance = enclosingInstance;
233 private BooleanScorer2 enclosingInstance;
234 public BooleanScorer2 Enclosing_Instance
238 return enclosingInstance;
242 private Scorer scorer;
243 private int lastScoredDoc = - 1;
245 internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer) : base(scorer.GetSimilarity())
247 InitBlock(enclosingInstance);
248 this.scorer = scorer;
250 public override float Score()
252 if (Doc() > lastScoredDoc)
254 lastScoredDoc = Doc();
255 Enclosing_Instance.coordinator.nrMatchers++;
257 return scorer.Score();
259 public override int Doc()
261 return scorer.Doc();
263 public override bool Next()
265 return scorer.Next();
267 public override bool SkipTo(int docNr)
269 return scorer.SkipTo(docNr);
271 public override Explanation Explain(int docNr)
273 return scorer.Explain(docNr);
277 private Scorer CountingDisjunctionSumScorer(System.Collections.IList scorers, int minMrShouldMatch)
278 // each scorer from the list counted as a single matcher
280 return new AnonymousClassDisjunctionSumScorer(this, scorers, minMrShouldMatch);
283 private static Similarity defaultSimilarity = new DefaultSimilarity();
285 private Scorer CountingConjunctionSumScorer(System.Collections.IList requiredScorers)
287 // each scorer from the list counted as a single matcher
288 int requiredNrMatchers = requiredScorers.Count;
289 ConjunctionScorer cs = new AnonymousClassConjunctionScorer(requiredNrMatchers, this, defaultSimilarity);
290 System.Collections.IEnumerator rsi = requiredScorers.GetEnumerator();
291 while (rsi.MoveNext())
293 cs.Add((Scorer) rsi.Current);
295 return cs;
298 private Scorer DualConjunctionSumScorer(Scorer req1, Scorer req2)
300 // non counting.
301 //UPGRADE_NOTE: Final was removed from the declaration of 'requiredNrMatchers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
302 int requiredNrMatchers = requiredScorers.Count;
303 ConjunctionScorer cs = new ConjunctionScorer(defaultSimilarity);
304 // All scorers match, so defaultSimilarity super.score() always has 1 as
305 // the coordination factor.
306 // Therefore the sum of the scores of two scorers
307 // is used as score.
308 cs.Add(req1);
309 cs.Add(req2);
310 return cs;
313 /// <summary>Returns the scorer to be used for match counting and score summing.
314 /// Uses requiredScorers, optionalScorers and prohibitedScorers.
315 /// </summary>
316 private Scorer MakeCountingSumScorer()
318 // each scorer counted as a single matcher
319 return (requiredScorers.Count == 0)?MakeCountingSumScorerNoReq():MakeCountingSumScorerSomeReq();
322 private Scorer MakeCountingSumScorerNoReq()
324 // No required scorers
325 if (optionalScorers.Count == 0)
327 return new NonMatchingScorer(); // no clauses or only prohibited clauses
329 else
331 // No required scorers. At least one optional scorer.
332 // minNrShouldMatch optional scorers are required, but at least 1
333 int nrOptRequired = (minNrShouldMatch < 1)?1:minNrShouldMatch;
334 if (optionalScorers.Count < nrOptRequired)
336 return new NonMatchingScorer(); // fewer optional clauses than minimum (at least 1) that should match
338 else
340 // optionalScorers.size() >= nrOptRequired, no required scorers
341 Scorer requiredCountingSumScorer = (optionalScorers.Count > nrOptRequired)?CountingDisjunctionSumScorer(optionalScorers, nrOptRequired):((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingConjunctionSumScorer(optionalScorers));
342 return AddProhibitedScorers(requiredCountingSumScorer);
347 private Scorer MakeCountingSumScorerSomeReq()
349 // At least one required scorer.
350 if (optionalScorers.Count < minNrShouldMatch)
352 return new NonMatchingScorer(); // fewer optional clauses than minimum that should match
354 else if (optionalScorers.Count == minNrShouldMatch)
356 // all optional scorers also required.
357 System.Collections.ArrayList allReq = new System.Collections.ArrayList(requiredScorers);
358 allReq.AddRange(optionalScorers);
359 return AddProhibitedScorers(CountingConjunctionSumScorer(allReq));
361 else
363 // optionalScorers.size() > minNrShouldMatch, and at least one required scorer
364 Scorer requiredCountingSumScorer = (requiredScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) requiredScorers[0]):CountingConjunctionSumScorer(requiredScorers);
365 if (minNrShouldMatch > 0)
367 // use a required disjunction scorer over the optional scorers
368 return AddProhibitedScorers(DualConjunctionSumScorer(requiredCountingSumScorer, CountingDisjunctionSumScorer(optionalScorers, minNrShouldMatch)));
370 else
372 // minNrShouldMatch == 0
373 return new ReqOptSumScorer(AddProhibitedScorers(requiredCountingSumScorer), ((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingDisjunctionSumScorer(optionalScorers, 1))); // require 1 in combined, optional scorer.
378 /// <summary>Returns the scorer to be used for match counting and score summing.
379 /// Uses the given required scorer and the prohibitedScorers.
380 /// </summary>
381 /// <param name="requiredCountingSumScorer">A required scorer already built.
382 /// </param>
383 private Scorer AddProhibitedScorers(Scorer requiredCountingSumScorer)
385 return (prohibitedScorers.Count == 0)?requiredCountingSumScorer:new ReqExclScorer(requiredCountingSumScorer, ((prohibitedScorers.Count == 1)?(Scorer) prohibitedScorers[0]:new DisjunctionSumScorer(prohibitedScorers)));
388 /// <summary>Scores and collects all matching documents.</summary>
389 /// <param name="hc">The collector to which all matching documents are passed through
390 /// {@link HitCollector#Collect(int, float)}.
391 /// <br>When this method is used the {@link #Explain(int)} method should not be used.
392 /// </param>
393 public override void Score(HitCollector hc)
395 if (countingSumScorer == null)
397 InitCountingSumScorer();
399 while (countingSumScorer.Next())
401 hc.Collect(countingSumScorer.Doc(), Score());
405 /// <summary>Expert: Collects matching documents in a range.
406 /// <br>Note that {@link #Next()} must be called once before this method is
407 /// called for the first time.
408 /// </summary>
409 /// <param name="hc">The collector to which all matching documents are passed through
410 /// {@link HitCollector#Collect(int, float)}.
411 /// </param>
412 /// <param name="max">Do not score documents past this.
413 /// </param>
414 /// <returns> true if more matching documents may remain.
415 /// </returns>
416 protected internal override bool Score(HitCollector hc, int max)
418 // null pointer exception when Next() was not called before:
419 int docNr = countingSumScorer.Doc();
420 while (docNr < max)
422 hc.Collect(docNr, Score());
423 if (!countingSumScorer.Next())
425 return false;
427 docNr = countingSumScorer.Doc();
429 return true;
432 public override int Doc()
434 return countingSumScorer.Doc();
437 public override bool Next()
439 if (countingSumScorer == null)
441 InitCountingSumScorer();
443 return countingSumScorer.Next();
446 public override float Score()
448 coordinator.InitDoc();
449 float sum = countingSumScorer.Score();
450 return sum * coordinator.CoordFactor();
453 /// <summary>Skips to the first match beyond the current whose document number is
454 /// greater than or equal to a given target.
455 ///
456 /// <p>When this method is used the {@link #Explain(int)} method should not be used.
457 ///
458 /// </summary>
459 /// <param name="target">The target document number.
460 /// </param>
461 /// <returns> true iff there is such a match.
462 /// </returns>
463 public override bool SkipTo(int target)
465 if (countingSumScorer == null)
467 InitCountingSumScorer();
469 return countingSumScorer.SkipTo(target);
472 /// <summary>Throws an UnsupportedOperationException.
473 /// TODO: Implement an explanation of the coordination factor.
474 /// </summary>
475 /// <param name="doc">The document number for the explanation.
476 /// </param>
477 /// <throws> UnsupportedOperationException </throws>
478 public override Explanation Explain(int doc)
480 throw new System.NotSupportedException();
481 /* How to explain the coordination factor?
482 initCountingSumScorer();
483 return countingSumScorer.explain(doc); // misses coord factor.