001 package gate.creole.annic.apache.lucene.search;
002
003 /**
004 * Copyright 2004 The Apache Software Foundation
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 import java.io.IOException;
020
021 final class BooleanScorer extends Scorer {
022 private SubScorer scorers = null;
023
024 private BucketTable bucketTable = new BucketTable(this);
025
026 private int maxCoord = 1;
027
028 private float[] coordFactors = null;
029
030 private int requiredMask = 0;
031
032 private int prohibitedMask = 0;
033
034 private int nextMask = 1;
035
036 BooleanScorer(Similarity similarity) {
037 super(similarity);
038 }
039
040 static final class SubScorer {
041 public Scorer scorer;
042
043 public boolean done;
044
045 public boolean required = false;
046
047 public boolean prohibited = false;
048
049 public HitCollector collector;
050
051 public SubScorer next;
052
053 protected Searcher searcher;
054
055 public SubScorer(Scorer scorer, boolean required, boolean prohibited,
056 HitCollector collector, SubScorer next) throws IOException {
057 this.searcher = scorer.searcher;
058 this.scorer = scorer;
059 this.done = !scorer.next(this.searcher);
060 this.required = required;
061 this.prohibited = prohibited;
062 this.collector = collector;
063 this.next = next;
064 }
065 }
066
067 final void add(Scorer scorer, boolean required, boolean prohibited)
068 throws IOException {
069 int mask = 0;
070 if(required || prohibited) {
071 if(nextMask == 0)
072 throw new IndexOutOfBoundsException(
073 "More than 32 required/prohibited clauses in query.");
074 mask = nextMask;
075 nextMask = nextMask << 1;
076 }
077 else mask = 0;
078
079 if(!prohibited) maxCoord++;
080
081 if(prohibited)
082 prohibitedMask |= mask; // update prohibited mask
083 else if(required) requiredMask |= mask; // update required mask
084
085 scorers = new SubScorer(scorer, required, prohibited, bucketTable
086 .newCollector(mask), scorers);
087 }
088
089 private final void computeCoordFactors() throws IOException {
090 coordFactors = new float[maxCoord];
091 for(int i = 0; i < maxCoord; i++)
092 coordFactors[i] = getSimilarity().coord(i, maxCoord - 1);
093 }
094
095 private int end;
096
097 private Bucket current;
098
099 public int doc() {
100 return current.doc;
101 }
102
103 public boolean next(Searcher searcher) throws IOException {
104 this.searcher = searcher;
105 boolean more;
106 do {
107 while(bucketTable.first != null) { // more queued
108 current = bucketTable.first;
109 bucketTable.first = current.next; // pop the queue
110
111 // check prohibited & required
112 if((current.bits & prohibitedMask) == 0
113 && (current.bits & requiredMask) == requiredMask) {
114 return true;
115 }
116 }
117
118 // refill the queue
119 more = false;
120 end += BucketTable.SIZE;
121 for(SubScorer sub = scorers; sub != null; sub = sub.next) {
122 Scorer scorer = sub.scorer;
123 while(!sub.done && scorer.doc() < end) {
124 sub.collector.collect(scorer.doc(), scorer.score(this.searcher));
125 sub.done = !scorer.next(this.searcher);
126 }
127 if(!sub.done) {
128 more = true;
129 }
130 }
131 } while(bucketTable.first != null | more);
132
133 return false;
134 }
135
136 public float score(Searcher searcher) throws IOException {
137 this.searcher = searcher;
138 if(coordFactors == null) computeCoordFactors();
139 return current.score * coordFactors[current.coord];
140 }
141
142 static final class Bucket {
143 int doc = -1; // tells if bucket is valid
144
145 float score; // incremental score
146
147 int bits; // used for bool constraints
148
149 int coord; // count of terms in score
150
151 Bucket next; // next valid bucket
152 }
153
154 /** A simple hash table of document scores within a range. */
155 static final class BucketTable {
156 public static final int SIZE = 1 << 10;
157
158 public static final int MASK = SIZE - 1;
159
160 final Bucket[] buckets = new Bucket[SIZE];
161
162 Bucket first = null; // head of valid list
163
164 private BooleanScorer scorer;
165
166 public BucketTable(BooleanScorer scorer) {
167 this.scorer = scorer;
168 }
169
170 public final int size() {
171 return SIZE;
172 }
173
174 public HitCollector newCollector(int mask) {
175 return new Collector(mask, this);
176 }
177 }
178
179 static final class Collector extends HitCollector {
180 private BucketTable bucketTable;
181
182 private int mask;
183
184 public Collector(int mask, BucketTable bucketTable) {
185 this.mask = mask;
186 this.bucketTable = bucketTable;
187 }
188
189 public final void collect(final int doc, final float score) {
190 final BucketTable table = bucketTable;
191 final int i = doc & BucketTable.MASK;
192 Bucket bucket = table.buckets[i];
193 if(bucket == null) table.buckets[i] = bucket = new Bucket();
194
195 if(bucket.doc != doc) { // invalid bucket
196 bucket.doc = doc; // set doc
197 bucket.score = score; // initialize score
198 bucket.bits = mask; // initialize mask
199 bucket.coord = 1; // initialize coord
200
201 bucket.next = table.first; // push onto valid list
202 table.first = bucket;
203 }
204 else { // valid bucket
205 bucket.score += score; // increment score
206 bucket.bits |= mask; // add bits in mask
207 bucket.coord++; // increment coord
208 }
209 }
210 }
211
212 public boolean skipTo(int target) throws IOException {
213 throw new UnsupportedOperationException();
214 }
215
216 public Explanation explain(int doc) throws IOException {
217 throw new UnsupportedOperationException();
218 }
219
220 public String toString() {
221 StringBuffer buffer = new StringBuffer();
222 buffer.append("boolean(");
223 for(SubScorer sub = scorers; sub != null; sub = sub.next) {
224 buffer.append(sub.scorer.toString());
225 buffer.append(" ");
226 }
227 buffer.append(")");
228 return buffer.toString();
229 }
230
231 }
|