/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace Lucene.Net.Search { /// An alternative to BooleanScorer. ///
Uses ConjunctionScorer, DisjunctionScorer, ReqOptScorer and ReqExclScorer. ///
Implements skipTo(), and has no limitations on the numbers of added scorers. ///
class BooleanScorer2 : Scorer { private class AnonymousClassDisjunctionSumScorer : DisjunctionSumScorer { private void InitBlock(BooleanScorer2 enclosingInstance) { this.enclosingInstance = enclosingInstance; } private BooleanScorer2 enclosingInstance; public BooleanScorer2 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassDisjunctionSumScorer(BooleanScorer2 enclosingInstance, System.Collections.IList Param1, int Param2):base(Param1, Param2) { InitBlock(enclosingInstance); } private int lastScoredDoc = - 1; public override float Score() { if (Doc() > lastScoredDoc) { lastScoredDoc = Doc(); Enclosing_Instance.coordinator.nrMatchers += base.nrMatchers; } return base.Score(); } } private class AnonymousClassConjunctionScorer : ConjunctionScorer { private void InitBlock(int requiredNrMatchers, BooleanScorer2 enclosingInstance) { this.requiredNrMatchers = requiredNrMatchers; this.enclosingInstance = enclosingInstance; } private int requiredNrMatchers; private BooleanScorer2 enclosingInstance; public BooleanScorer2 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassConjunctionScorer(int requiredNrMatchers, BooleanScorer2 enclosingInstance, Lucene.Net.Search.Similarity Param1):base(Param1) { InitBlock(requiredNrMatchers, enclosingInstance); } private int lastScoredDoc = - 1; public override float Score() { if (Doc() > lastScoredDoc) { lastScoredDoc = Doc(); Enclosing_Instance.coordinator.nrMatchers += requiredNrMatchers; } // All scorers match, so defaultSimilarity super.score() always has 1 as // the coordination factor. // Therefore the sum of the scores of the requiredScorers // is used as score. return base.Score(); } } private System.Collections.ArrayList requiredScorers = new System.Collections.ArrayList(); private System.Collections.ArrayList optionalScorers = new System.Collections.ArrayList(); private System.Collections.ArrayList prohibitedScorers = new System.Collections.ArrayList(); private class Coordinator { public Coordinator(BooleanScorer2 enclosingInstance) { InitBlock(enclosingInstance); } private void InitBlock(BooleanScorer2 enclosingInstance) { this.enclosingInstance = enclosingInstance; } private BooleanScorer2 enclosingInstance; public BooleanScorer2 Enclosing_Instance { get { return enclosingInstance; } } internal int maxCoord = 0; // to be increased for each non prohibited scorer private float[] coordFactors = null; internal virtual void Init() { // use after all scorers have been added. coordFactors = new float[maxCoord + 1]; Similarity sim = Enclosing_Instance.GetSimilarity(); for (int i = 0; i <= maxCoord; i++) { coordFactors[i] = sim.Coord(i, maxCoord); } } internal int nrMatchers; // to be increased by score() of match counting scorers. internal virtual void InitDoc() { nrMatchers = 0; } internal virtual float CoordFactor() { return coordFactors[nrMatchers]; } } private Coordinator coordinator; /// The scorer to which all scoring will be delegated, /// except for computing and using the coordination factor. /// private Scorer countingSumScorer = null; /// The number of optionalScorers that need to match (if there are any) private int minNrShouldMatch; /// Create a BooleanScorer2. /// The similarity to be used. /// /// The minimum number of optional added scorers /// that should match during the search. /// In case no required scorers are added, /// at least one of the optional scorers will have to /// match during the search. /// public BooleanScorer2(Similarity similarity, int minNrShouldMatch):base(similarity) { if (minNrShouldMatch < 0) { throw new System.ArgumentException("Minimum number of optional scorers should not be negative"); } coordinator = new Coordinator(this); this.minNrShouldMatch = minNrShouldMatch; } /// Create a BooleanScorer2. /// In no required scorers are added, /// at least one of the optional scorers will have to match during the search. /// /// The similarity to be used. /// public BooleanScorer2(Similarity similarity) : this(similarity, 0) { } public virtual void Add(Scorer scorer, bool required, bool prohibited) { if (!prohibited) { coordinator.maxCoord++; } if (required) { if (prohibited) { throw new System.ArgumentException("scorer cannot be required and prohibited"); } requiredScorers.Add(scorer); } else if (prohibited) { prohibitedScorers.Add(scorer); } else { optionalScorers.Add(scorer); } } /// Initialize the match counting scorer that sums all the /// scores.

/// When "counting" is used in a name it means counting the number /// of matching scorers.
/// When "sum" is used in a name it means score value summing /// over the matching scorers ///

private void InitCountingSumScorer() { coordinator.Init(); countingSumScorer = MakeCountingSumScorer(); } /// Count a scorer as a single match. private class SingleMatchScorer : Scorer { private void InitBlock(BooleanScorer2 enclosingInstance) { this.enclosingInstance = enclosingInstance; } private BooleanScorer2 enclosingInstance; public BooleanScorer2 Enclosing_Instance { get { return enclosingInstance; } } private Scorer scorer; private int lastScoredDoc = - 1; internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer) : base(scorer.GetSimilarity()) { InitBlock(enclosingInstance); this.scorer = scorer; } public override float Score() { if (Doc() > lastScoredDoc) { lastScoredDoc = Doc(); Enclosing_Instance.coordinator.nrMatchers++; } return scorer.Score(); } public override int Doc() { return scorer.Doc(); } public override bool Next() { return scorer.Next(); } public override bool SkipTo(int docNr) { return scorer.SkipTo(docNr); } public override Explanation Explain(int docNr) { return scorer.Explain(docNr); } } private Scorer CountingDisjunctionSumScorer(System.Collections.IList scorers, int minMrShouldMatch) // each scorer from the list counted as a single matcher { return new AnonymousClassDisjunctionSumScorer(this, scorers, minMrShouldMatch); } private static Similarity defaultSimilarity = new DefaultSimilarity(); private Scorer CountingConjunctionSumScorer(System.Collections.IList requiredScorers) { // each scorer from the list counted as a single matcher int requiredNrMatchers = requiredScorers.Count; ConjunctionScorer cs = new AnonymousClassConjunctionScorer(requiredNrMatchers, this, defaultSimilarity); System.Collections.IEnumerator rsi = requiredScorers.GetEnumerator(); while (rsi.MoveNext()) { cs.Add((Scorer) rsi.Current); } return cs; } private Scorer DualConjunctionSumScorer(Scorer req1, Scorer req2) { // non counting. //UPGRADE_NOTE: Final was removed from the declaration of 'requiredNrMatchers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" int requiredNrMatchers = requiredScorers.Count; ConjunctionScorer cs = new ConjunctionScorer(defaultSimilarity); // All scorers match, so defaultSimilarity super.score() always has 1 as // the coordination factor. // Therefore the sum of the scores of two scorers // is used as score. cs.Add(req1); cs.Add(req2); return cs; } /// Returns the scorer to be used for match counting and score summing. /// Uses requiredScorers, optionalScorers and prohibitedScorers. /// private Scorer MakeCountingSumScorer() { // each scorer counted as a single matcher return (requiredScorers.Count == 0)?MakeCountingSumScorerNoReq():MakeCountingSumScorerSomeReq(); } private Scorer MakeCountingSumScorerNoReq() { // No required scorers if (optionalScorers.Count == 0) { return new NonMatchingScorer(); // no clauses or only prohibited clauses } else { // No required scorers. At least one optional scorer. // minNrShouldMatch optional scorers are required, but at least 1 int nrOptRequired = (minNrShouldMatch < 1)?1:minNrShouldMatch; if (optionalScorers.Count < nrOptRequired) { return new NonMatchingScorer(); // fewer optional clauses than minimum (at least 1) that should match } else { // optionalScorers.size() >= nrOptRequired, no required scorers Scorer requiredCountingSumScorer = (optionalScorers.Count > nrOptRequired)?CountingDisjunctionSumScorer(optionalScorers, nrOptRequired):((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingConjunctionSumScorer(optionalScorers)); return AddProhibitedScorers(requiredCountingSumScorer); } } } private Scorer MakeCountingSumScorerSomeReq() { // At least one required scorer. if (optionalScorers.Count < minNrShouldMatch) { return new NonMatchingScorer(); // fewer optional clauses than minimum that should match } else if (optionalScorers.Count == minNrShouldMatch) { // all optional scorers also required. System.Collections.ArrayList allReq = new System.Collections.ArrayList(requiredScorers); allReq.AddRange(optionalScorers); return AddProhibitedScorers(CountingConjunctionSumScorer(allReq)); } else { // optionalScorers.size() > minNrShouldMatch, and at least one required scorer Scorer requiredCountingSumScorer = (requiredScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) requiredScorers[0]):CountingConjunctionSumScorer(requiredScorers); if (minNrShouldMatch > 0) { // use a required disjunction scorer over the optional scorers return AddProhibitedScorers(DualConjunctionSumScorer(requiredCountingSumScorer, CountingDisjunctionSumScorer(optionalScorers, minNrShouldMatch))); } else { // minNrShouldMatch == 0 return new ReqOptSumScorer(AddProhibitedScorers(requiredCountingSumScorer), ((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingDisjunctionSumScorer(optionalScorers, 1))); // require 1 in combined, optional scorer. } } } /// Returns the scorer to be used for match counting and score summing. /// Uses the given required scorer and the prohibitedScorers. /// /// A required scorer already built. /// private Scorer AddProhibitedScorers(Scorer requiredCountingSumScorer) { return (prohibitedScorers.Count == 0)?requiredCountingSumScorer:new ReqExclScorer(requiredCountingSumScorer, ((prohibitedScorers.Count == 1)?(Scorer) prohibitedScorers[0]:new DisjunctionSumScorer(prohibitedScorers))); } /// Scores and collects all matching documents. /// The collector to which all matching documents are passed through /// {@link HitCollector#Collect(int, float)}. ///
When this method is used the {@link #Explain(int)} method should not be used. /// public override void Score(HitCollector hc) { if (countingSumScorer == null) { InitCountingSumScorer(); } while (countingSumScorer.Next()) { hc.Collect(countingSumScorer.Doc(), Score()); } } /// Expert: Collects matching documents in a range. ///
Note that {@link #Next()} must be called once before this method is /// called for the first time. ///
/// The collector to which all matching documents are passed through /// {@link HitCollector#Collect(int, float)}. /// /// Do not score documents past this. /// /// true if more matching documents may remain. /// protected internal override bool Score(HitCollector hc, int max) { // null pointer exception when Next() was not called before: int docNr = countingSumScorer.Doc(); while (docNr < max) { hc.Collect(docNr, Score()); if (!countingSumScorer.Next()) { return false; } docNr = countingSumScorer.Doc(); } return true; } public override int Doc() { return countingSumScorer.Doc(); } public override bool Next() { if (countingSumScorer == null) { InitCountingSumScorer(); } return countingSumScorer.Next(); } public override float Score() { coordinator.InitDoc(); float sum = countingSumScorer.Score(); return sum * coordinator.CoordFactor(); } /// Skips to the first match beyond the current whose document number is /// greater than or equal to a given target. /// ///

When this method is used the {@link #Explain(int)} method should not be used. /// ///

/// The target document number. /// /// true iff there is such a match. /// public override bool SkipTo(int target) { if (countingSumScorer == null) { InitCountingSumScorer(); } return countingSumScorer.SkipTo(target); } /// Throws an UnsupportedOperationException. /// TODO: Implement an explanation of the coordination factor. /// /// The document number for the explanation. /// /// UnsupportedOperationException public override Explanation Explain(int doc) { throw new System.NotSupportedException(); /* How to explain the coordination factor? initCountingSumScorer(); return countingSumScorer.explain(doc); // misses coord factor. */ } } }