1 package org.apache.lucene.search;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 import org.apache.lucene.util.ArrayUtil;
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Comparator;
25 /** Scorer for conjunctions, sets of queries, all of which are required. */
26 class ConjunctionScorer extends Scorer {
28 private final Scorer[] scorers;
29 private final float coord;
30 private int lastDoc = -1;
32 public ConjunctionScorer(Weight weight, float coord, Collection<Scorer> scorers) throws IOException {
33 this(weight, coord, scorers.toArray(new Scorer[scorers.size()]));
36 public ConjunctionScorer(Weight weight, float coord, Scorer... scorers) throws IOException {
38 this.scorers = scorers;
41 for (int i = 0; i < scorers.length; i++) {
42 if (scorers[i].nextDoc() == NO_MORE_DOCS) {
43 // If even one of the sub-scorers does not have any documents, this
44 // scorer should not attempt to do any more work.
45 lastDoc = NO_MORE_DOCS;
50 // Sort the array the first time...
51 // We don't need to sort the array in any future calls because we know
52 // it will already start off sorted (all scorers on same doc).
54 // Note that this comparator is not consistent with equals!
55 // Also we use mergeSort here to be stable (so order of Scoreres that
56 // match on first document keeps preserved):
57 ArrayUtil.mergeSort(scorers, new Comparator<Scorer>() { // sort the array
58 public int compare(Scorer o1, Scorer o2) {
59 return o1.docID() - o2.docID();
63 // NOTE: doNext() must be called before the re-sorting of the array later on.
64 // The reason is this: assume there are 5 scorers, whose first docs are 1,
65 // 2, 3, 5, 5 respectively. Sorting (above) leaves the array as is. Calling
66 // doNext() here advances all the first scorers to 5 (or a larger doc ID
67 // they all agree on).
68 // However, if we re-sort before doNext() is called, the order will be 5, 3,
69 // 2, 1, 5 and then doNext() will stop immediately, since the first scorer's
70 // docs equals the last one. So the invariant that after calling doNext()
71 // all scorers are on the same doc ID is broken.
72 if (doNext() == NO_MORE_DOCS) {
73 // The scorers did not agree on any document.
74 lastDoc = NO_MORE_DOCS;
78 // If first-time skip distance is any predictor of
79 // scorer sparseness, then we should always try to skip first on
81 // Keep last scorer in it's last place (it will be the first
82 // to be skipped on), but reverse all of the others so that
83 // they will be skipped on in order of original high skip.
84 int end = scorers.length - 1;
86 for (int i = 0; i < max; i++) {
87 Scorer tmp = scorers[i];
88 int idx = end - i - 1;
89 scorers[i] = scorers[idx];
94 private int doNext() throws IOException {
96 int doc = scorers[scorers.length - 1].docID();
98 while ((firstScorer = scorers[first]).docID() < doc) {
99 doc = firstScorer.advance(doc);
100 first = first == scorers.length - 1 ? 0 : first + 1;
106 public int advance(int target) throws IOException {
107 if (lastDoc == NO_MORE_DOCS) {
109 } else if (scorers[(scorers.length - 1)].docID() < target) {
110 scorers[(scorers.length - 1)].advance(target);
112 return lastDoc = doNext();
121 public int nextDoc() throws IOException {
122 if (lastDoc == NO_MORE_DOCS) {
124 } else if (lastDoc == -1) {
125 return lastDoc = scorers[scorers.length - 1].docID();
127 scorers[(scorers.length - 1)].nextDoc();
128 return lastDoc = doNext();
132 public float score() throws IOException {
134 for (int i = 0; i < scorers.length; i++) {
135 sum += scorers[i].score();