/* * 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 { /* See the description in BooleanScorer.java, comparing * BooleanScorer & BooleanScorer2 */ /// An alternative to BooleanScorer that also allows a minimum number /// of optional scorers that should match. ///
Implements skipTo(), and has no limitations on the numbers of added scorers. ///
Uses ConjunctionScorer, DisjunctionScorer, ReqOptScorer and ReqExclScorer. ///
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.Generic.IList scorers, int minNrShouldMatch) : base(scorers, minNrShouldMatch) { InitBlock(enclosingInstance); } private int lastScoredDoc = - 1; // Save the score of lastScoredDoc, so that we don't compute it more than // once in score(). private float lastDocScore = System.Single.NaN; public override float Score() { int doc = DocID(); if (doc >= lastScoredDoc) { if (doc > lastScoredDoc) { lastDocScore = base.Score(); lastScoredDoc = doc; } Enclosing_Instance.coordinator.nrMatchers += base.nrMatchers; } return lastDocScore; } } 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 defaultSimilarity, System.Collections.Generic.IList requiredScorers) : base(defaultSimilarity, requiredScorers) { InitBlock(requiredNrMatchers, enclosingInstance); } private int lastScoredDoc = - 1; // Save the score of lastScoredDoc, so that we don't compute it more than // once in score(). private float lastDocScore = System.Single.NaN; public override float Score() { int doc = DocID(); if (doc >= lastScoredDoc) { if (doc > lastScoredDoc) { lastDocScore = base.Score(); 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 lastDocScore; } } private System.Collections.Generic.List requiredScorers; private System.Collections.Generic.List optionalScorers; private System.Collections.Generic.List prohibitedScorers; 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 float[] coordFactors = null; internal int maxCoord = 0; // to be increased for each non prohibited scorer internal int nrMatchers; // to be increased by score() of match counting scorers. internal virtual void Init() { // use after all scorers have been added. coordFactors = new float[maxCoord + 1]; Similarity sim = Enclosing_Instance.Similarity; for (int i = 0; i <= maxCoord; i++) { coordFactors[i] = sim.Coord(i, maxCoord); } } } private Coordinator coordinator; /// The scorer to which all scoring will be delegated, /// except for computing and using the coordination factor. /// private Scorer countingSumScorer; /// The number of optionalScorers that need to match (if there are any) private int minNrShouldMatch; private int doc = - 1; /// Creates a with the given similarity and lists of required, /// prohibited and optional scorers. 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. /// /// 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. /// /// the list of required scorers. /// /// the list of prohibited scorers. /// /// the list of optional scorers. /// public BooleanScorer2(Similarity similarity, int minNrShouldMatch, System.Collections.Generic.List required, System.Collections.Generic.List prohibited, System.Collections.Generic.List optional) : 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; optionalScorers = optional; coordinator.maxCoord += optional.Count; requiredScorers = required; coordinator.maxCoord += required.Count; prohibitedScorers = prohibited; 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; // Save the score of lastScoredDoc, so that we don't compute it more than // once in score(). private float lastDocScore = System.Single.NaN; internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer):base(scorer.Similarity) { InitBlock(enclosingInstance); this.scorer = scorer; } public override float Score() { int doc = DocID(); if (doc >= lastScoredDoc) { if (doc > lastScoredDoc) { lastDocScore = scorer.Score(); lastScoredDoc = doc; } Enclosing_Instance.coordinator.nrMatchers++; } return lastDocScore; } public override int DocID() { return scorer.DocID(); } public override int NextDoc() { return scorer.NextDoc(); } public override int Advance(int target) { return scorer.Advance(target); } } private Scorer CountingDisjunctionSumScorer(System.Collections.Generic.List scorers, int minNrShouldMatch) { // each scorer from the list counted as a single matcher return new AnonymousClassDisjunctionSumScorer(this, scorers, minNrShouldMatch); } private static readonly Similarity defaultSimilarity; private Scorer CountingConjunctionSumScorer(System.Collections.Generic.List requiredScorers) { // each scorer from the list counted as a single matcher int requiredNrMatchers = requiredScorers.Count; return new AnonymousClassConjunctionScorer(requiredNrMatchers, this, defaultSimilarity, requiredScorers); } private Scorer DualConjunctionSumScorer(Scorer req1, Scorer req2) { // non counting. return new ConjunctionScorer(defaultSimilarity, new Scorer[]{req1, req2}); // All scorers match, so defaultSimilarity always has 1 as // the coordination factor. // Therefore the sum of the scores of two scorers // is used as score. } /// 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 // minNrShouldMatch optional scorers are required, but at least 1 int nrOptRequired = (minNrShouldMatch < 1)?1:minNrShouldMatch; Scorer requiredCountingSumScorer; if (optionalScorers.Count > nrOptRequired) requiredCountingSumScorer = CountingDisjunctionSumScorer(optionalScorers, nrOptRequired); else if (optionalScorers.Count == 1) requiredCountingSumScorer = new SingleMatchScorer(this, optionalScorers[0]); else requiredCountingSumScorer = CountingConjunctionSumScorer(optionalScorers); return AddProhibitedScorers(requiredCountingSumScorer); } private Scorer MakeCountingSumScorerSomeReq() { // At least one required scorer. if (optionalScorers.Count == minNrShouldMatch) { // all optional scorers also required. var allReq = new System.Collections.Generic.List(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, 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, optionalScorers[0]) : CountingDisjunctionSumScorer(optionalScorers, 1)); } } } /// 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) ? prohibitedScorers[0] : new DisjunctionSumScorer(prohibitedScorers))); } /// Scores and collects all matching documents. /// The collector to which all matching documents are passed through. /// public override void Score(Collector collector) { collector.SetScorer(this); while ((doc = countingSumScorer.NextDoc()) != NO_MORE_DOCS) { collector.Collect(doc); } } public /*protected internal*/ override bool Score(Collector collector, int max, int firstDocID) { doc = firstDocID; collector.SetScorer(this); while (doc < max) { collector.Collect(doc); doc = countingSumScorer.NextDoc(); } return doc != NO_MORE_DOCS; } public override int DocID() { return doc; } public override int NextDoc() { return doc = countingSumScorer.NextDoc(); } public override float Score() { coordinator.nrMatchers = 0; float sum = countingSumScorer.Score(); return sum * coordinator.coordFactors[coordinator.nrMatchers]; } public override int Advance(int target) { return doc = countingSumScorer.Advance(target); } static BooleanScorer2() { defaultSimilarity = Search.Similarity.Default; } } }