BooleanScorer.java
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 nextthrows 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(!prohibitedmaxCoord++;
080 
081     if(prohibited)
082       prohibitedMask |= mask; // update prohibited mask
083     else if(requiredrequiredMask |= 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 searcherthrows 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 searcherthrows IOException {
137     this.searcher = searcher;
138     if(coordFactors == nullcomputeCoordFactors();
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 = << 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 == nulltable.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 targetthrows IOException {
213     throw new UnsupportedOperationException();
214   }
215 
216   public Explanation explain(int docthrows 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 }