2 * Copyright 2005 The Apache Software Foundation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
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
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
;
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
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
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()
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.
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.
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.
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.
182 /// <param name="similarity">The similarity to be used.
184 public BooleanScorer2(Similarity similarity
) : this(similarity
, 0)
188 public virtual void Add(Scorer scorer
, bool required
, bool prohibited
)
192 coordinator
.maxCoord
++;
199 throw new System
.ArgumentException("scorer cannot be required and prohibited");
201 requiredScorers
.Add(scorer
);
205 prohibitedScorers
.Add(scorer
);
209 optionalScorers
.Add(scorer
);
213 /// <summary>Initialize the match counting scorer that sums all the
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
220 private void InitCountingSumScorer()
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()
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
);
298 private Scorer
DualConjunctionSumScorer(Scorer req1
, Scorer req2
)
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
313 /// <summary>Returns the scorer to be used for match counting and score summing.
314 /// Uses requiredScorers, optionalScorers and prohibitedScorers.
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
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
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
));
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
)));
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.
381 /// <param name="requiredCountingSumScorer">A required scorer already built.
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.
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.
409 /// <param name="hc">The collector to which all matching documents are passed through
410 /// {@link HitCollector#Collect(int, float)}.
412 /// <param name="max">Do not score documents past this.
414 /// <returns> true if more matching documents may remain.
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();
422 hc
.Collect(docNr
, Score());
423 if (!countingSumScorer
.Next())
427 docNr
= countingSumScorer
.Doc();
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.
456 /// <p>When this method is used the {@link #Explain(int)} method should not be used.
459 /// <param name="target">The target document number.
461 /// <returns> true iff there is such a match.
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.
475 /// <param name="doc">The document number for the explanation.
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.