X-Git-Url: https://git.mdrn.pl/pylucene.git/blobdiff_plain/a2e61f0c04805cfcb8706176758d1283c7e3a55c..aaeed5504b982cf3545252ab528713250aa33eed:/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/search/ConjunctionScorer.java?ds=sidebyside diff --git a/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/search/ConjunctionScorer.java b/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/search/ConjunctionScorer.java new file mode 100644 index 0000000..b8dea25 --- /dev/null +++ b/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/search/ConjunctionScorer.java @@ -0,0 +1,139 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import org.apache.lucene.util.ArrayUtil; +import java.io.IOException; +import java.util.Collection; +import java.util.Comparator; + +/** Scorer for conjunctions, sets of queries, all of which are required. */ +class ConjunctionScorer extends Scorer { + + private final Scorer[] scorers; + private final float coord; + private int lastDoc = -1; + + public ConjunctionScorer(Weight weight, float coord, Collection scorers) throws IOException { + this(weight, coord, scorers.toArray(new Scorer[scorers.size()])); + } + + public ConjunctionScorer(Weight weight, float coord, Scorer... scorers) throws IOException { + super(weight); + this.scorers = scorers; + this.coord = coord; + + for (int i = 0; i < scorers.length; i++) { + if (scorers[i].nextDoc() == NO_MORE_DOCS) { + // If even one of the sub-scorers does not have any documents, this + // scorer should not attempt to do any more work. + lastDoc = NO_MORE_DOCS; + return; + } + } + + // Sort the array the first time... + // We don't need to sort the array in any future calls because we know + // it will already start off sorted (all scorers on same doc). + + // Note that this comparator is not consistent with equals! + // Also we use mergeSort here to be stable (so order of Scoreres that + // match on first document keeps preserved): + ArrayUtil.mergeSort(scorers, new Comparator() { // sort the array + public int compare(Scorer o1, Scorer o2) { + return o1.docID() - o2.docID(); + } + }); + + // NOTE: doNext() must be called before the re-sorting of the array later on. + // The reason is this: assume there are 5 scorers, whose first docs are 1, + // 2, 3, 5, 5 respectively. Sorting (above) leaves the array as is. Calling + // doNext() here advances all the first scorers to 5 (or a larger doc ID + // they all agree on). + // However, if we re-sort before doNext() is called, the order will be 5, 3, + // 2, 1, 5 and then doNext() will stop immediately, since the first scorer's + // docs equals the last one. So the invariant that after calling doNext() + // all scorers are on the same doc ID is broken. + if (doNext() == NO_MORE_DOCS) { + // The scorers did not agree on any document. + lastDoc = NO_MORE_DOCS; + return; + } + + // If first-time skip distance is any predictor of + // scorer sparseness, then we should always try to skip first on + // those scorers. + // Keep last scorer in it's last place (it will be the first + // to be skipped on), but reverse all of the others so that + // they will be skipped on in order of original high skip. + int end = scorers.length - 1; + int max = end >> 1; + for (int i = 0; i < max; i++) { + Scorer tmp = scorers[i]; + int idx = end - i - 1; + scorers[i] = scorers[idx]; + scorers[idx] = tmp; + } + } + + private int doNext() throws IOException { + int first = 0; + int doc = scorers[scorers.length - 1].docID(); + Scorer firstScorer; + while ((firstScorer = scorers[first]).docID() < doc) { + doc = firstScorer.advance(doc); + first = first == scorers.length - 1 ? 0 : first + 1; + } + return doc; + } + + @Override + public int advance(int target) throws IOException { + if (lastDoc == NO_MORE_DOCS) { + return lastDoc; + } else if (scorers[(scorers.length - 1)].docID() < target) { + scorers[(scorers.length - 1)].advance(target); + } + return lastDoc = doNext(); + } + + @Override + public int docID() { + return lastDoc; + } + + @Override + public int nextDoc() throws IOException { + if (lastDoc == NO_MORE_DOCS) { + return lastDoc; + } else if (lastDoc == -1) { + return lastDoc = scorers[scorers.length - 1].docID(); + } + scorers[(scorers.length - 1)].nextDoc(); + return lastDoc = doNext(); + } + + @Override + public float score() throws IOException { + float sum = 0.0f; + for (int i = 0; i < scorers.length; i++) { + sum += scorers[i].score(); + } + return sum * coord; + } +}