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();