001: package org.apache.lucene.search;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021: import java.util.Collection;
022: import java.util.Arrays;
023: import java.util.Comparator;
024:
025: /** Scorer for conjunctions, sets of queries, all of which are required. */
026: class ConjunctionScorer extends Scorer {
027: private final Scorer[] scorers;
028:
029: private boolean firstTime = true;
030: private boolean more;
031: private final float coord;
032: private int lastDoc = -1;
033:
034: public ConjunctionScorer(Similarity similarity, Collection scorers)
035: throws IOException {
036: this (similarity, (Scorer[]) scorers.toArray(new Scorer[scorers
037: .size()]));
038: }
039:
040: public ConjunctionScorer(Similarity similarity, Scorer[] scorers)
041: throws IOException {
042: super (similarity);
043: this .scorers = scorers;
044: coord = getSimilarity().coord(this .scorers.length,
045: this .scorers.length);
046: }
047:
048: public int doc() {
049: return lastDoc;
050: }
051:
052: public boolean next() throws IOException {
053: if (firstTime)
054: return init(0);
055: else if (more)
056: more = scorers[(scorers.length - 1)].next();
057: return doNext();
058: }
059:
060: private boolean doNext() throws IOException {
061: int first = 0;
062: Scorer lastScorer = scorers[scorers.length - 1];
063: Scorer firstScorer;
064: while (more
065: && (firstScorer = scorers[first]).doc() < (lastDoc = lastScorer
066: .doc())) {
067: more = firstScorer.skipTo(lastDoc);
068: lastScorer = firstScorer;
069: first = (first == (scorers.length - 1)) ? 0 : first + 1;
070: }
071: return more;
072: }
073:
074: public boolean skipTo(int target) throws IOException {
075: if (firstTime)
076: return init(target);
077: else if (more)
078: more = scorers[(scorers.length - 1)].skipTo(target);
079: return doNext();
080: }
081:
082: // Note... most of this could be done in the constructor
083: // thus skipping a check for firstTime per call to next() and skipTo()
084: private boolean init(int target) throws IOException {
085: firstTime = false;
086: more = scorers.length > 1;
087: for (int i = 0; i < scorers.length; i++) {
088: more = target == 0 ? scorers[i].next() : scorers[i]
089: .skipTo(target);
090: if (!more)
091: return false;
092: }
093:
094: // Sort the array the first time...
095: // We don't need to sort the array in any future calls because we know
096: // it will already start off sorted (all scorers on same doc).
097:
098: // note that this comparator is not consistent with equals!
099: Arrays.sort(scorers, new Comparator() { // sort the array
100: public int compare(Object o1, Object o2) {
101: return ((Scorer) o1).doc()
102: - ((Scorer) o2).doc();
103: }
104: });
105:
106: doNext();
107:
108: // If first-time skip distance is any predictor of
109: // scorer sparseness, then we should always try to skip first on
110: // those scorers.
111: // Keep last scorer in it's last place (it will be the first
112: // to be skipped on), but reverse all of the others so that
113: // they will be skipped on in order of original high skip.
114: int end = (scorers.length - 1) - 1;
115: for (int i = 0; i < (end >> 1); i++) {
116: Scorer tmp = scorers[i];
117: scorers[i] = scorers[end - i];
118: scorers[end - i] = tmp;
119: }
120:
121: return more;
122: }
123:
124: public float score() throws IOException {
125: float sum = 0.0f;
126: for (int i = 0; i < scorers.length; i++) {
127: sum += scorers[i].score();
128: }
129: return sum * coord;
130: }
131:
132: public Explanation explain(int doc) {
133: throw new UnsupportedOperationException();
134: }
135:
136: }
|