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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 namespace Mono.Lucene.Net.Search
23 /* See the description in BooleanScorer.java, comparing
24 * BooleanScorer & BooleanScorer2 */
26 /// <summary>An alternative to BooleanScorer that also allows a minimum number
27 /// of optional scorers that should match.
28 /// <br/>Implements skipTo(), and has no limitations on the numbers of added scorers.
29 /// <br/>Uses ConjunctionScorer, DisjunctionScorer, ReqOptScorer and ReqExclScorer.
31 class BooleanScorer2:Scorer
33 private class AnonymousClassDisjunctionSumScorer:DisjunctionSumScorer
35 private void InitBlock(BooleanScorer2 enclosingInstance)
37 this.enclosingInstance = enclosingInstance;
39 private BooleanScorer2 enclosingInstance;
40 public BooleanScorer2 Enclosing_Instance
44 return enclosingInstance;
48 internal AnonymousClassDisjunctionSumScorer(BooleanScorer2 enclosingInstance, System.Collections.IList Param1, int Param2):base(Param1, Param2)
50 InitBlock(enclosingInstance);
52 private int lastScoredDoc = - 1;
53 // Save the score of lastScoredDoc, so that we don't compute it more than
55 private float lastDocScore = System.Single.NaN;
56 public override float Score()
59 if (doc >= lastScoredDoc)
61 if (doc > lastScoredDoc)
63 lastDocScore = base.Score();
66 Enclosing_Instance.coordinator.nrMatchers += base.nrMatchers;
71 private class AnonymousClassConjunctionScorer:ConjunctionScorer
73 private void InitBlock(int requiredNrMatchers, BooleanScorer2 enclosingInstance)
75 this.requiredNrMatchers = requiredNrMatchers;
76 this.enclosingInstance = enclosingInstance;
78 private int requiredNrMatchers;
79 private BooleanScorer2 enclosingInstance;
80 public BooleanScorer2 Enclosing_Instance
84 return enclosingInstance;
88 internal AnonymousClassConjunctionScorer(int requiredNrMatchers, BooleanScorer2 enclosingInstance, Mono.Lucene.Net.Search.Similarity Param1, System.Collections.ICollection Param2):base(Param1, Param2)
90 InitBlock(requiredNrMatchers, enclosingInstance);
92 private int lastScoredDoc = - 1;
93 // Save the score of lastScoredDoc, so that we don't compute it more than
95 private float lastDocScore = System.Single.NaN;
96 public override float Score()
99 if (doc >= lastScoredDoc)
101 if (doc > lastScoredDoc)
103 lastDocScore = base.Score();
106 Enclosing_Instance.coordinator.nrMatchers += requiredNrMatchers;
108 // All scorers match, so defaultSimilarity super.score() always has 1 as
109 // the coordination factor.
110 // Therefore the sum of the scores of the requiredScorers
116 private System.Collections.IList requiredScorers;
117 private System.Collections.IList optionalScorers;
118 private System.Collections.IList prohibitedScorers;
120 private class Coordinator
122 public Coordinator(BooleanScorer2 enclosingInstance)
124 InitBlock(enclosingInstance);
126 private void InitBlock(BooleanScorer2 enclosingInstance)
128 this.enclosingInstance = enclosingInstance;
130 private BooleanScorer2 enclosingInstance;
131 public BooleanScorer2 Enclosing_Instance
135 return enclosingInstance;
139 internal float[] coordFactors = null;
140 internal int maxCoord = 0; // to be increased for each non prohibited scorer
141 internal int nrMatchers; // to be increased by score() of match counting scorers.
143 internal virtual void Init()
145 // use after all scorers have been added.
146 coordFactors = new float[maxCoord + 1];
147 Similarity sim = Enclosing_Instance.GetSimilarity();
148 for (int i = 0; i <= maxCoord; i++)
150 coordFactors[i] = sim.Coord(i, maxCoord);
155 private Coordinator coordinator;
157 /// <summary>The scorer to which all scoring will be delegated,
158 /// except for computing and using the coordination factor.
160 private Scorer countingSumScorer;
162 /// <summary>The number of optionalScorers that need to match (if there are any) </summary>
163 private int minNrShouldMatch;
165 private int doc = - 1;
167 /// <summary> Creates a {@link Scorer} with the given similarity and lists of required,
168 /// prohibited and optional scorers. In no required scorers are added, at least
169 /// one of the optional scorers will have to match during the search.
172 /// <param name="similarity">The similarity to be used.
174 /// <param name="minNrShouldMatch">The minimum number of optional added scorers that should match
175 /// during the search. In case no required scorers are added, at least
176 /// one of the optional scorers will have to match during the search.
178 /// <param name="required">the list of required scorers.
180 /// <param name="prohibited">the list of prohibited scorers.
182 /// <param name="optional">the list of optional scorers.
184 public BooleanScorer2(Similarity similarity, int minNrShouldMatch, System.Collections.IList required, System.Collections.IList prohibited, System.Collections.IList optional):base(similarity)
186 if (minNrShouldMatch < 0)
188 throw new System.ArgumentException("Minimum number of optional scorers should not be negative");
190 coordinator = new Coordinator(this);
191 this.minNrShouldMatch = minNrShouldMatch;
193 optionalScorers = optional;
194 coordinator.maxCoord += optional.Count;
196 requiredScorers = required;
197 coordinator.maxCoord += required.Count;
199 prohibitedScorers = prohibited;
202 countingSumScorer = MakeCountingSumScorer();
205 /// <summary>Count a scorer as a single match. </summary>
206 private class SingleMatchScorer:Scorer
208 private void InitBlock(BooleanScorer2 enclosingInstance)
210 this.enclosingInstance = enclosingInstance;
212 private BooleanScorer2 enclosingInstance;
213 public BooleanScorer2 Enclosing_Instance
217 return enclosingInstance;
221 private Scorer scorer;
222 private int lastScoredDoc = - 1;
223 // Save the score of lastScoredDoc, so that we don't compute it more than
225 private float lastDocScore = System.Single.NaN;
227 internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer):base(scorer.GetSimilarity())
229 InitBlock(enclosingInstance);
230 this.scorer = scorer;
232 public override float Score()
235 if (doc >= lastScoredDoc)
237 if (doc > lastScoredDoc)
239 lastDocScore = scorer.Score();
242 Enclosing_Instance.coordinator.nrMatchers++;
246 /// <deprecated> use {@link #DocID()} instead.
248 [Obsolete("use DocID() instead. ")]
249 public override int Doc()
253 public override int DocID()
255 return scorer.DocID();
257 /// <deprecated> use {@link #NextDoc()} instead.
259 [Obsolete("use NextDoc() instead. ")]
260 public override bool Next()
262 return scorer.NextDoc() != NO_MORE_DOCS;
264 public override int NextDoc()
266 return scorer.NextDoc();
268 /// <deprecated> use {@link #Advance(int)} instead.
270 [Obsolete("use Advance(int) instead. ")]
271 public override bool SkipTo(int docNr)
273 return scorer.Advance(docNr) != NO_MORE_DOCS;
275 public override int Advance(int target)
277 return scorer.Advance(target);
279 public override Explanation Explain(int docNr)
281 return scorer.Explain(docNr);
285 private Scorer CountingDisjunctionSumScorer(System.Collections.IList scorers, int minNrShouldMatch)
287 // each scorer from the list counted as a single matcher
288 return new AnonymousClassDisjunctionSumScorer(this, scorers, minNrShouldMatch);
291 private static readonly Similarity defaultSimilarity;
293 private Scorer CountingConjunctionSumScorer(System.Collections.IList requiredScorers)
295 // each scorer from the list counted as a single matcher
296 int requiredNrMatchers = requiredScorers.Count;
297 return new AnonymousClassConjunctionScorer(requiredNrMatchers, this, defaultSimilarity, requiredScorers);
300 private Scorer DualConjunctionSumScorer(Scorer req1, Scorer req2)
303 return new ConjunctionScorer(defaultSimilarity, new Scorer[]{req1, req2});
304 // All scorers match, so defaultSimilarity always has 1 as
305 // the coordination factor.
306 // Therefore the sum of the scores of two scorers
310 /// <summary>Returns the scorer to be used for match counting and score summing.
311 /// Uses requiredScorers, optionalScorers and prohibitedScorers.
313 private Scorer MakeCountingSumScorer()
315 // each scorer counted as a single matcher
316 return (requiredScorers.Count == 0)?MakeCountingSumScorerNoReq():MakeCountingSumScorerSomeReq();
319 private Scorer MakeCountingSumScorerNoReq()
321 // No required scorers
322 // minNrShouldMatch optional scorers are required, but at least 1
323 int nrOptRequired = (minNrShouldMatch < 1)?1:minNrShouldMatch;
324 Scorer requiredCountingSumScorer;
325 if (optionalScorers.Count > nrOptRequired)
326 requiredCountingSumScorer = CountingDisjunctionSumScorer(optionalScorers, nrOptRequired);
327 else if (optionalScorers.Count == 1)
328 requiredCountingSumScorer = new SingleMatchScorer(this, (Scorer) optionalScorers[0]);
330 requiredCountingSumScorer = CountingConjunctionSumScorer(optionalScorers);
331 return AddProhibitedScorers(requiredCountingSumScorer);
334 private Scorer MakeCountingSumScorerSomeReq()
336 // At least one required scorer.
337 if (optionalScorers.Count == minNrShouldMatch)
339 // all optional scorers also required.
340 System.Collections.ArrayList allReq = new System.Collections.ArrayList(requiredScorers);
341 allReq.AddRange(optionalScorers);
342 return AddProhibitedScorers(CountingConjunctionSumScorer(allReq));
346 // optionalScorers.size() > minNrShouldMatch, and at least one required scorer
347 Scorer requiredCountingSumScorer = requiredScorers.Count == 1?new SingleMatchScorer(this, (Scorer) requiredScorers[0]):CountingConjunctionSumScorer(requiredScorers);
348 if (minNrShouldMatch > 0)
350 // use a required disjunction scorer over the optional scorers
351 return AddProhibitedScorers(DualConjunctionSumScorer(requiredCountingSumScorer, CountingDisjunctionSumScorer(optionalScorers, minNrShouldMatch)));
355 // minNrShouldMatch == 0
356 return new ReqOptSumScorer(AddProhibitedScorers(requiredCountingSumScorer), optionalScorers.Count == 1?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingDisjunctionSumScorer(optionalScorers, 1));
361 /// <summary>Returns the scorer to be used for match counting and score summing.
362 /// Uses the given required scorer and the prohibitedScorers.
364 /// <param name="requiredCountingSumScorer">A required scorer already built.
366 private Scorer AddProhibitedScorers(Scorer requiredCountingSumScorer)
368 return (prohibitedScorers.Count == 0)?requiredCountingSumScorer:new ReqExclScorer(requiredCountingSumScorer, ((prohibitedScorers.Count == 1)?(Scorer) prohibitedScorers[0]:new DisjunctionSumScorer(prohibitedScorers)));
371 /// <summary>Scores and collects all matching documents.</summary>
372 /// <param name="hc">The collector to which all matching documents are passed through
373 /// {@link HitCollector#Collect(int, float)}.
374 /// <br/>When this method is used the {@link #Explain(int)} method should not be used.
376 /// <deprecated> use {@link #Score(Collector)} instead.
378 [Obsolete("use Score(Collector) instead.")]
379 public override void Score(HitCollector hc)
381 Score(new HitCollectorWrapper(hc));
384 /// <summary>Scores and collects all matching documents.</summary>
385 /// <param name="collector">The collector to which all matching documents are passed through.
386 /// <br/>When this method is used the {@link #Explain(int)} method should not be used.
388 public override void Score(Collector collector)
390 collector.SetScorer(this);
391 while ((doc = countingSumScorer.NextDoc()) != NO_MORE_DOCS)
393 collector.Collect(doc);
397 /// <summary>Expert: Collects matching documents in a range.
398 /// <br/>Note that {@link #Next()} must be called once before this method is
399 /// called for the first time.
401 /// <param name="hc">The collector to which all matching documents are passed through
402 /// {@link HitCollector#Collect(int, float)}.
404 /// <param name="max">Do not score documents past this.
406 /// <returns> true if more matching documents may remain.
408 /// <deprecated> use {@link #Score(Collector, int, int)} instead.
410 [Obsolete("use Score(Collector, int, int) instead.")]
411 protected internal override bool Score(HitCollector hc, int max)
413 return Score(new HitCollectorWrapper(hc), max, DocID());
416 public /*protected internal*/ override bool Score(Collector collector, int max, int firstDocID)
419 collector.SetScorer(this);
422 collector.Collect(doc);
423 doc = countingSumScorer.NextDoc();
425 return doc != NO_MORE_DOCS;
428 /// <deprecated> use {@link #DocID()} instead.
430 [Obsolete("use DocID() instead. ")]
431 public override int Doc()
433 return countingSumScorer.Doc();
436 public override int DocID()
441 /// <deprecated> use {@link #NextDoc()} instead.
443 [Obsolete("use NextDoc() instead. ")]
444 public override bool Next()
446 return NextDoc() != NO_MORE_DOCS;
449 public override int NextDoc()
451 return doc = countingSumScorer.NextDoc();
454 public override float Score()
456 coordinator.nrMatchers = 0;
457 float sum = countingSumScorer.Score();
458 return sum * coordinator.coordFactors[coordinator.nrMatchers];
461 /// <deprecated> use {@link #Advance(int)} instead.
463 [Obsolete("use Advance(int) instead. ")]
464 public override bool SkipTo(int target)
466 return Advance(target) != NO_MORE_DOCS;
469 public override int Advance(int target)
471 return doc = countingSumScorer.Advance(target);
474 /// <summary>Throws an UnsupportedOperationException.
475 /// TODO: Implement an explanation of the coordination factor.
477 /// <param name="doc">The document number for the explanation.
479 /// <throws> UnsupportedOperationException </throws>
480 public override Explanation Explain(int doc)
482 throw new System.NotSupportedException();
483 /* How to explain the coordination factor?
484 initCountingSumScorer();
485 return countingSumScorer.explain(doc); // misses coord factor.
488 static BooleanScorer2()
490 defaultSimilarity = Similarity.GetDefault();