~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/src/java/org/apache/lucene/search/DisjunctionSumScorer.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.apache.lucene.search;
2
 
 
3
 
/**
4
 
 * Licensed to the Apache Software Foundation (ASF) under one or more
5
 
 * contributor license agreements.  See the NOTICE file distributed with
6
 
 * this work for additional information regarding copyright ownership.
7
 
 * The ASF licenses this file to You under the Apache License, Version 2.0
8
 
 * (the "License"); you may not use this file except in compliance with
9
 
 * the License.  You may obtain a copy of the License at
10
 
 *
11
 
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 
 *
13
 
 * Unless required by applicable law or agreed to in writing, software
14
 
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 
 * See the License for the specific language governing permissions and
17
 
 * limitations under the License.
18
 
 */
19
 
 
20
 
import java.util.List;
21
 
import java.io.IOException;
22
 
 
23
 
import org.apache.lucene.util.ScorerDocQueue;
24
 
 
25
 
/** A Scorer for OR like queries, counterpart of <code>ConjunctionScorer</code>.
26
 
 * This Scorer implements {@link Scorer#skipTo(int)} and uses skipTo() on the given Scorers. 
27
 
 */
28
 
class DisjunctionSumScorer extends Scorer {
29
 
  /** The number of subscorers. */ 
30
 
  private final int nrScorers;
31
 
  
32
 
  /** The subscorers. */
33
 
  protected final List<Scorer> subScorers;
34
 
  
35
 
  /** The minimum number of scorers that should match. */
36
 
  private final int minimumNrMatchers;
37
 
  
38
 
  /** The scorerDocQueue contains all subscorers ordered by their current doc(),
39
 
   * with the minimum at the top.
40
 
   * <br>The scorerDocQueue is initialized the first time next() or skipTo() is called.
41
 
   * <br>An exhausted scorer is immediately removed from the scorerDocQueue.
42
 
   * <br>If less than the minimumNrMatchers scorers
43
 
   * remain in the scorerDocQueue next() and skipTo() return false.
44
 
   * <p>
45
 
   * After each to call to next() or skipTo()
46
 
   * <code>currentSumScore</code> is the total score of the current matching doc,
47
 
   * <code>nrMatchers</code> is the number of matching scorers,
48
 
   * and all scorers are after the matching doc, or are exhausted.
49
 
   */
50
 
  private ScorerDocQueue scorerDocQueue;
51
 
  
52
 
  /** The document number of the current match. */
53
 
  private int currentDoc = -1;
54
 
 
55
 
  /** The number of subscorers that provide the current match. */
56
 
  protected int nrMatchers = -1;
57
 
 
58
 
  private double currentScore = Float.NaN;
59
 
  
60
 
  /** Construct a <code>DisjunctionScorer</code>.
61
 
   * @param weight The weight to be used.
62
 
   * @param subScorers A collection of at least two subscorers.
63
 
   * @param minimumNrMatchers The positive minimum number of subscorers that should
64
 
   * match to match this query.
65
 
   * <br>When <code>minimumNrMatchers</code> is bigger than
66
 
   * the number of <code>subScorers</code>,
67
 
   * no matches will be produced.
68
 
   * <br>When minimumNrMatchers equals the number of subScorers,
69
 
   * it more efficient to use <code>ConjunctionScorer</code>.
70
 
   */
71
 
  public DisjunctionSumScorer(Weight weight, List<Scorer> subScorers, int minimumNrMatchers) throws IOException {
72
 
    super(weight);
73
 
    
74
 
    nrScorers = subScorers.size();
75
 
 
76
 
    if (minimumNrMatchers <= 0) {
77
 
      throw new IllegalArgumentException("Minimum nr of matchers must be positive");
78
 
    }
79
 
    if (nrScorers <= 1) {
80
 
      throw new IllegalArgumentException("There must be at least 2 subScorers");
81
 
    }
82
 
 
83
 
    this.minimumNrMatchers = minimumNrMatchers;
84
 
    this.subScorers = subScorers;
85
 
 
86
 
    initScorerDocQueue();
87
 
  }
88
 
  
89
 
  /** Construct a <code>DisjunctionScorer</code>, using one as the minimum number
90
 
   * of matching subscorers.
91
 
   */
92
 
  public DisjunctionSumScorer(Weight weight, List<Scorer> subScorers) throws IOException {
93
 
    this(weight, subScorers, 1);
94
 
  }
95
 
 
96
 
  /** Called the first time next() or skipTo() is called to
97
 
   * initialize <code>scorerDocQueue</code>.
98
 
   */
99
 
  private void initScorerDocQueue() throws IOException {
100
 
    scorerDocQueue = new ScorerDocQueue(nrScorers);
101
 
    for (Scorer se : subScorers) {
102
 
      if (se.nextDoc() != NO_MORE_DOCS) {
103
 
        scorerDocQueue.insert(se);
104
 
      }
105
 
    }
106
 
  }
107
 
 
108
 
  /** Scores and collects all matching documents.
109
 
   * @param collector The collector to which all matching documents are passed through.
110
 
   */
111
 
  @Override
112
 
  public void score(Collector collector) throws IOException {
113
 
    collector.setScorer(this);
114
 
    while (nextDoc() != NO_MORE_DOCS) {
115
 
      collector.collect(currentDoc);
116
 
    }
117
 
  }
118
 
 
119
 
  /** Expert: Collects matching documents in a range.  Hook for optimization.
120
 
   * Note that {@link #next()} must be called once before this method is called
121
 
   * for the first time.
122
 
   * @param collector The collector to which all matching documents are passed through.
123
 
   * @param max Do not score documents past this.
124
 
   * @return true if more matching documents may remain.
125
 
   */
126
 
  @Override
127
 
  protected boolean score(Collector collector, int max, int firstDocID) throws IOException {
128
 
    // firstDocID is ignored since nextDoc() sets 'currentDoc'
129
 
    collector.setScorer(this);
130
 
    while (currentDoc < max) {
131
 
      collector.collect(currentDoc);
132
 
      if (nextDoc() == NO_MORE_DOCS) {
133
 
        return false;
134
 
      }
135
 
    }
136
 
    return true;
137
 
  }
138
 
 
139
 
  @Override
140
 
  public int nextDoc() throws IOException {
141
 
    if (scorerDocQueue.size() < minimumNrMatchers || !advanceAfterCurrent()) {
142
 
      currentDoc = NO_MORE_DOCS;
143
 
    }
144
 
    return currentDoc;
145
 
  }
146
 
 
147
 
  /** Advance all subscorers after the current document determined by the
148
 
   * top of the <code>scorerDocQueue</code>.
149
 
   * Repeat until at least the minimum number of subscorers match on the same
150
 
   * document and all subscorers are after that document or are exhausted.
151
 
   * <br>On entry the <code>scorerDocQueue</code> has at least <code>minimumNrMatchers</code>
152
 
   * available. At least the scorer with the minimum document number will be advanced.
153
 
   * @return true iff there is a match.
154
 
   * <br>In case there is a match, </code>currentDoc</code>, </code>currentSumScore</code>,
155
 
   * and </code>nrMatchers</code> describe the match.
156
 
   *
157
 
   * TODO: Investigate whether it is possible to use skipTo() when
158
 
   * the minimum number of matchers is bigger than one, ie. try and use the
159
 
   * character of ConjunctionScorer for the minimum number of matchers.
160
 
   * Also delay calling score() on the sub scorers until the minimum number of
161
 
   * matchers is reached.
162
 
   * <br>For this, a Scorer array with minimumNrMatchers elements might
163
 
   * hold Scorers at currentDoc that are temporarily popped from scorerQueue.
164
 
   */
165
 
  protected boolean advanceAfterCurrent() throws IOException {
166
 
    do { // repeat until minimum nr of matchers
167
 
      currentDoc = scorerDocQueue.topDoc();
168
 
      currentScore = scorerDocQueue.topScore();
169
 
      nrMatchers = 1;
170
 
      do { // Until all subscorers are after currentDoc
171
 
        if (!scorerDocQueue.topNextAndAdjustElsePop()) {
172
 
          if (scorerDocQueue.size() == 0) {
173
 
            break; // nothing more to advance, check for last match.
174
 
          }
175
 
        }
176
 
        if (scorerDocQueue.topDoc() != currentDoc) {
177
 
          break; // All remaining subscorers are after currentDoc.
178
 
        }
179
 
        currentScore += scorerDocQueue.topScore();
180
 
        nrMatchers++;
181
 
      } while (true);
182
 
      
183
 
      if (nrMatchers >= minimumNrMatchers) {
184
 
        return true;
185
 
      } else if (scorerDocQueue.size() < minimumNrMatchers) {
186
 
        return false;
187
 
      }
188
 
    } while (true);
189
 
  }
190
 
  
191
 
  /** Returns the score of the current document matching the query.
192
 
   * Initially invalid, until {@link #nextDoc()} is called the first time.
193
 
   */
194
 
  @Override
195
 
  public float score() throws IOException { return (float)currentScore; }
196
 
   
197
 
  @Override
198
 
  public int docID() {
199
 
    return currentDoc;
200
 
  }
201
 
  
202
 
  /** Returns the number of subscorers matching the current document.
203
 
   * Initially invalid, until {@link #nextDoc()} is called the first time.
204
 
   */
205
 
  public int nrMatchers() {
206
 
    return nrMatchers;
207
 
  }
208
 
 
209
 
  /**
210
 
   * Advances to the first match beyond the current whose document number is
211
 
   * greater than or equal to a given target. <br>
212
 
   * The implementation uses the skipTo() method on the subscorers.
213
 
   * 
214
 
   * @param target
215
 
   *          The target document number.
216
 
   * @return the document whose number is greater than or equal to the given
217
 
   *         target, or -1 if none exist.
218
 
   */
219
 
  @Override
220
 
  public int advance(int target) throws IOException {
221
 
    if (scorerDocQueue.size() < minimumNrMatchers) {
222
 
      return currentDoc = NO_MORE_DOCS;
223
 
    }
224
 
    if (target <= currentDoc) {
225
 
      return currentDoc;
226
 
    }
227
 
    do {
228
 
      if (scorerDocQueue.topDoc() >= target) {
229
 
        return advanceAfterCurrent() ? currentDoc : (currentDoc = NO_MORE_DOCS);
230
 
      } else if (!scorerDocQueue.topSkipToAndAdjustElsePop(target)) {
231
 
        if (scorerDocQueue.size() < minimumNrMatchers) {
232
 
          return currentDoc = NO_MORE_DOCS;
233
 
        }
234
 
      }
235
 
    } while (true);
236
 
  }
237
 
}