add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / java / org / apache / lucene / search / ConjunctionScorer.java
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 org.apache.lucene.util.ArrayUtil;
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Comparator;
24
25 /** Scorer for conjunctions, sets of queries, all of which are required. */
26 class ConjunctionScorer extends Scorer {
27   
28   private final Scorer[] scorers;
29   private final float coord;
30   private int lastDoc = -1;
31
32   public ConjunctionScorer(Weight weight, float coord, Collection<Scorer> scorers) throws IOException {
33     this(weight, coord, scorers.toArray(new Scorer[scorers.size()]));
34   }
35
36   public ConjunctionScorer(Weight weight, float coord, Scorer... scorers) throws IOException {
37     super(weight);
38     this.scorers = scorers;
39     this.coord = coord;
40     
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;
46         return;
47       }
48     }
49
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).
53     
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();
60       }
61     });
62
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;
75       return;
76     }
77
78     // If first-time skip distance is any predictor of
79     // scorer sparseness, then we should always try to skip first on
80     // those scorers.
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;
85     int max = end >> 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];
90       scorers[idx] = tmp;
91     }
92   }
93
94   private int doNext() throws IOException {
95     int first = 0;
96     int doc = scorers[scorers.length - 1].docID();
97     Scorer firstScorer;
98     while ((firstScorer = scorers[first]).docID() < doc) {
99       doc = firstScorer.advance(doc);
100       first = first == scorers.length - 1 ? 0 : first + 1;
101     }
102     return doc;
103   }
104   
105   @Override
106   public int advance(int target) throws IOException {
107     if (lastDoc == NO_MORE_DOCS) {
108       return lastDoc;
109     } else if (scorers[(scorers.length - 1)].docID() < target) {
110       scorers[(scorers.length - 1)].advance(target);
111     }
112     return lastDoc = doNext();
113   }
114
115   @Override
116   public int docID() {
117     return lastDoc;
118   }
119   
120   @Override
121   public int nextDoc() throws IOException {
122     if (lastDoc == NO_MORE_DOCS) {
123       return lastDoc;
124     } else if (lastDoc == -1) {
125       return lastDoc = scorers[scorers.length - 1].docID();
126     }
127     scorers[(scorers.length - 1)].nextDoc();
128     return lastDoc = doNext();
129   }
130   
131   @Override
132   public float score() throws IOException {
133     float sum = 0.0f;
134     for (int i = 0; i < scorers.length; i++) {
135       sum += scorers[i].score();
136     }
137     return sum * coord;
138   }
139 }