/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed 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.
///
public 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) : base(Param1)
{
InitBlock(enclosingInstance);
}
public override float Score()
{
Enclosing_Instance.coordinator.nrMatchers += 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);
}
public override float Score()
{
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;
public BooleanScorer2(Similarity similarity) : base(similarity)
{
coordinator = new Coordinator(this);
}
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;
internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer):base(scorer.GetSimilarity())
{
InitBlock(enclosingInstance);
this.scorer = scorer;
}
public override float Score()
{
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)
// each scorer from the list counted as a single matcher
{
return new AnonymousClassDisjunctionSumScorer(this, scorers);
}
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;
}
/// 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
{
if (requiredScorers.Count == 0)
{
if (optionalScorers.Count == 0)
{
return new NonMatchingScorer(); // only prohibited scorers
}
else if (optionalScorers.Count == 1)
{
return MakeCountingSumScorer2(new SingleMatchScorer(this, (Scorer) optionalScorers[0]), new System.Collections.ArrayList()); // no optional scorers left
}
else
{
// more than 1 optionalScorers, no required scorers
return MakeCountingSumScorer2(CountingDisjunctionSumScorer(optionalScorers), new System.Collections.ArrayList()); // no optional scorers left
}
}
else if (requiredScorers.Count == 1)
{
// 1 required
return MakeCountingSumScorer2(new SingleMatchScorer(this, (Scorer) requiredScorers[0]), optionalScorers);
}
else
{
// more required scorers
return MakeCountingSumScorer2(CountingConjunctionSumScorer(requiredScorers), optionalScorers);
}
}
/// Returns the scorer to be used for match counting and score summing.
/// Uses the arguments and prohibitedScorers.
///
/// A required scorer already built.
///
/// A list of optional scorers, possibly empty.
///
private Scorer MakeCountingSumScorer2(Scorer requiredCountingSumScorer, System.Collections.IList optionalScorers)
// not match counting
{
if (optionalScorers.Count == 0)
{
// no optional
if (prohibitedScorers.Count == 0)
{
// no prohibited
return requiredCountingSumScorer;
}
else if (prohibitedScorers.Count == 1)
{
// no optional, 1 prohibited
return new ReqExclScorer(requiredCountingSumScorer, (Scorer) prohibitedScorers[0]); // not match counting
}
else
{
// no optional, more prohibited
return new ReqExclScorer(requiredCountingSumScorer, new DisjunctionSumScorer(prohibitedScorers)); // score unused. not match counting
}
}
else if (optionalScorers.Count == 1)
{
// 1 optional
return MakeCountingSumScorer3(requiredCountingSumScorer, new SingleMatchScorer(this, (Scorer) optionalScorers[0]));
}
else
{
// more optional
return MakeCountingSumScorer3(requiredCountingSumScorer, CountingDisjunctionSumScorer(optionalScorers));
}
}
/// Returns the scorer to be used for match counting and score summing.
/// Uses the arguments and prohibitedScorers.
///
/// A required scorer already built.
///
/// An optional scorer already built.
///
private Scorer MakeCountingSumScorer3(Scorer requiredCountingSumScorer, Scorer optionalCountingSumScorer)
{
if (prohibitedScorers.Count == 0)
{
// no prohibited
return new ReqOptSumScorer(requiredCountingSumScorer, optionalCountingSumScorer);
}
else if (prohibitedScorers.Count == 1)
{
// 1 prohibited
return new ReqOptSumScorer(new ReqExclScorer(requiredCountingSumScorer, (Scorer) prohibitedScorers[0]), optionalCountingSumScorer);
}
else
{
// more prohibited
return new ReqOptSumScorer(new ReqExclScorer(requiredCountingSumScorer, new DisjunctionSumScorer(prohibitedScorers)), optionalCountingSumScorer);
}
}
/// 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();
}
public override bool SkipTo(int target)
{
if (countingSumScorer == null)
{
InitCountingSumScorer();
}
return countingSumScorer.SkipTo(target);
}
public override Explanation Explain(int doc)
{
throw new System.NotSupportedException();
/* How to explain the coordination factor?
initCountingSumScorer();
return countingSumScorer.explain(doc); // misses coord factor.
*/
}
}
}