FileDocCategorySizeDatePackage
DisjunctionSumScorer.javaAPI DocApache Lucene 2.1.09732Wed Feb 14 10:46:40 GMT 2007org.apache.lucene.search

DisjunctionSumScorer

public class DisjunctionSumScorer extends Scorer
A Scorer for OR like queries, counterpart of ConjunctionScorer. This Scorer implements {@link Scorer#skipTo(int)} and uses skipTo() on the given Scorers.
todo
Implement score(HitCollector, int).

Fields Summary
private final int
nrScorers
The number of subscorers.
protected final List
subScorers
The subscorers.
private final int
minimumNrMatchers
The minimum number of scorers that should match.
private ScorerDocQueue
scorerDocQueue
The scorerDocQueue contains all subscorers ordered by their current doc(), with the minimum at the top.
The scorerDocQueue is initialized the first time next() or skipTo() is called.
An exhausted scorer is immediately removed from the scorerDocQueue.
If less than the minimumNrMatchers scorers remain in the scorerDocQueue next() and skipTo() return false.

After each to call to next() or skipTo() currentSumScore is the total score of the current matching doc, nrMatchers is the number of matching scorers, and all scorers are after the matching doc, or are exhausted.

private int
queueSize
private int
currentDoc
The document number of the current match.
protected int
nrMatchers
The number of subscorers that provide the current match.
private float
currentScore
Constructors Summary
public DisjunctionSumScorer(List subScorers, int minimumNrMatchers)
Construct a DisjunctionScorer.

param
subScorers A collection of at least two subscorers.
param
minimumNrMatchers The positive minimum number of subscorers that should match to match this query.
When minimumNrMatchers is bigger than the number of subScorers, no matches will be produced.
When minimumNrMatchers equals the number of subScorers, it more efficient to use ConjunctionScorer.

  
                                                           
        
    super(null);
    
    nrScorers = subScorers.size();

    if (minimumNrMatchers <= 0) {
      throw new IllegalArgumentException("Minimum nr of matchers must be positive");
    }
    if (nrScorers <= 1) {
      throw new IllegalArgumentException("There must be at least 2 subScorers");
    }

    this.minimumNrMatchers = minimumNrMatchers;
    this.subScorers = subScorers;
  
public DisjunctionSumScorer(List subScorers)
Construct a DisjunctionScorer, using one as the minimum number of matching subscorers.

    this(subScorers, 1);
  
Methods Summary
protected booleanadvanceAfterCurrent()
Advance all subscorers after the current document determined by the top of the scorerDocQueue. Repeat until at least the minimum number of subscorers match on the same document and all subscorers are after that document or are exhausted.
On entry the scorerDocQueue has at least minimumNrMatchers available. At least the scorer with the minimum document number will be advanced.

return
true iff there is a match.
In case there is a match, currentDoc, currentSumScore, and nrMatchers describe the match.
todo
Investigate whether it is possible to use skipTo() when the minimum number of matchers is bigger than one, ie. try and use the character of ConjunctionScorer for the minimum number of matchers. Also delay calling score() on the sub scorers until the minimum number of matchers is reached.
For this, a Scorer array with minimumNrMatchers elements might hold Scorers at currentDoc that are temporarily popped from scorerQueue.

    do { // repeat until minimum nr of matchers
      currentDoc = scorerDocQueue.topDoc();
      currentScore = scorerDocQueue.topScore();
      nrMatchers = 1;
      do { // Until all subscorers are after currentDoc
        if (! scorerDocQueue.topNextAndAdjustElsePop()) {
          if (--queueSize == 0) {
            break; // nothing more to advance, check for last match.
          }
        }
        if (scorerDocQueue.topDoc() != currentDoc) {
          break; // All remaining subscorers are after currentDoc.
        }
        currentScore += scorerDocQueue.topScore();
        nrMatchers++;
      } while (true);
      
      if (nrMatchers >= minimumNrMatchers) {
        return true;
      } else if (queueSize < minimumNrMatchers) {
        return false;
      }
    } while (true);
  
public intdoc()

 return currentDoc; 
public org.apache.lucene.search.Explanationexplain(int doc)

return
An explanation for the score of a given document.

    Explanation res = new Explanation();
    Iterator ssi = subScorers.iterator();
    float sumScore = 0.0f;
    int nrMatches = 0;
    while (ssi.hasNext()) {
      Explanation es = ((Scorer) ssi.next()).explain(doc);
      if (es.getValue() > 0.0f) { // indicates match
        sumScore += es.getValue();
        nrMatches++;
      }
      res.addDetail(es);
    }
    if (nrMatchers >= minimumNrMatchers) {
      res.setValue(sumScore);
      res.setDescription("sum over at least " + minimumNrMatchers
                         + " of " + subScorers.size() + ":");
    } else {
      res.setValue(0.0f);
      res.setDescription(nrMatches + " match(es) but at least "
                         + minimumNrMatchers + " of "
                         + subScorers.size() + " needed");
    }
    return res;
  
private voidinitScorerDocQueue()
Called the first time next() or skipTo() is called to initialize scorerDocQueue.

    Iterator si = subScorers.iterator();
    scorerDocQueue = new ScorerDocQueue(nrScorers);
    queueSize = 0;
    while (si.hasNext()) {
      Scorer se = (Scorer) si.next();
      if (se.next()) { // doc() method will be used in scorerDocQueue.
        if (scorerDocQueue.insert(se)) {
          queueSize++;
        }
      }
    }
  
public booleannext()

    if (scorerDocQueue == null) {
      initScorerDocQueue();
    }
    return (scorerDocQueue.size() >= minimumNrMatchers)
          && advanceAfterCurrent();
  
public intnrMatchers()
Returns the number of subscorers matching the current document. Initially invalid, until {@link #next()} is called the first time.

    return nrMatchers;
  
public voidscore(org.apache.lucene.search.HitCollector hc)
Scores and collects all matching documents.

param
hc 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.

    while (next()) {
      hc.collect(currentDoc, currentScore);
    }
  
protected booleanscore(org.apache.lucene.search.HitCollector hc, int max)
Expert: Collects matching documents in a range. Hook for optimization. Note that {@link #next()} must be called once before this method is called for the first time.

param
hc The collector to which all matching documents are passed through {@link HitCollector#collect(int, float)}.
param
max Do not score documents past this.
return
true if more matching documents may remain.

    while (currentDoc < max) {
      hc.collect(currentDoc, currentScore);
      if (!next()) {
        return false;
      }
    }
    return true;
  
public floatscore()
Returns the score of the current document matching the query. Initially invalid, until {@link #next()} is called the first time.

 return currentScore; 
public booleanskipTo(int target)
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 implementation uses the skipTo() method on the subscorers.

param
target The target document number.
return
true iff there is such a match.

    if (scorerDocQueue == null) {
      initScorerDocQueue();
    }
    if (queueSize < minimumNrMatchers) {
      return false;
    }
    if (target <= currentDoc) {
      return true;
    }
    do {
      if (scorerDocQueue.topDoc() >= target) {
        return advanceAfterCurrent();
      } else if (! scorerDocQueue.topSkipToAndAdjustElsePop(target)) {
        if (--queueSize < minimumNrMatchers) {
          return false;
        }
      }
    } while (true);