QueryResponses.cs, DumpIndex.cs, IQueryResult.cs, QueryExecutor.cs, QueryResult.cs...
[beagle.git] / beagled / Lucene.Net / Search / BooleanScorer.cs
blob3d1ba885d3b50011a18138c237d3a9a97c734601
1 /*
2 * Copyright 2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 using System;
19 namespace Lucene.Net.Search
22 sealed class BooleanScorer : Scorer
24 private void InitBlock()
26 bucketTable = new BucketTable(this);
28 private SubScorer scorers = null;
29 private BucketTable bucketTable;
31 private int maxCoord = 1;
32 private float[] coordFactors = null;
34 private int requiredMask = 0;
35 private int prohibitedMask = 0;
36 private int nextMask = 1;
38 internal BooleanScorer(Similarity similarity) : base(similarity)
40 InitBlock();
43 internal sealed class SubScorer
45 public Scorer scorer;
46 public bool done;
47 public bool required = false;
48 public bool prohibited = false;
49 public HitCollector collector;
50 public SubScorer next;
52 public SubScorer(Scorer scorer, bool required, bool prohibited, HitCollector collector, SubScorer next)
54 this.scorer = scorer;
55 this.done = !scorer.Next();
56 this.required = required;
57 this.prohibited = prohibited;
58 this.collector = collector;
59 this.next = next;
63 internal void Add(Scorer scorer, bool required, bool prohibited)
65 int mask = 0;
66 if (required || prohibited)
68 if (nextMask == 0)
69 throw new System.IndexOutOfRangeException("More than 32 required/prohibited clauses in query.");
70 mask = nextMask;
71 nextMask = nextMask << 1;
73 else
74 mask = 0;
76 if (!prohibited)
77 maxCoord++;
79 if (prohibited)
80 prohibitedMask |= mask;
81 // update prohibited mask
82 else if (required)
83 requiredMask |= mask; // update required mask
85 scorers = new SubScorer(scorer, required, prohibited, bucketTable.NewCollector(mask), scorers);
88 private void ComputeCoordFactors()
90 coordFactors = new float[maxCoord];
91 for (int i = 0; i < maxCoord; i++)
92 coordFactors[i] = GetSimilarity().Coord(i, maxCoord - 1);
95 private int end;
96 private Bucket current;
98 public override void Score(HitCollector hc)
100 Next();
101 Score(hc, System.Int32.MaxValue);
104 protected internal override bool Score(HitCollector hc, int max)
106 if (coordFactors == null)
107 ComputeCoordFactors();
109 bool more;
110 Bucket tmp;
114 bucketTable.first = null;
116 while (current != null)
118 // more queued
120 // check prohibited & required
121 if ((current.bits & prohibitedMask) == 0 && (current.bits & requiredMask) == requiredMask)
124 if (current.doc >= max)
126 tmp = current;
127 current = current.next;
128 tmp.next = bucketTable.first;
129 bucketTable.first = tmp;
130 continue;
133 hc.Collect(current.doc, current.score * coordFactors[current.coord]);
136 current = current.next; // pop the queue
139 if (bucketTable.first != null)
141 current = bucketTable.first;
142 bucketTable.first = current.next;
143 return true;
146 // refill the queue
147 more = false;
148 end += BucketTable.SIZE;
149 for (SubScorer sub = scorers; sub != null; sub = sub.next)
151 if (!sub.done)
153 sub.done = !sub.scorer.Score(sub.collector, end);
154 if (!sub.done)
155 more = true;
158 current = bucketTable.first;
160 while (current != null || more);
162 return false;
165 public override int Doc()
167 return current.doc;
170 public override bool Next()
172 bool more;
175 while (bucketTable.first != null)
177 // more queued
178 current = bucketTable.first;
179 bucketTable.first = current.next; // pop the queue
181 // check prohibited & required
182 if ((current.bits & prohibitedMask) == 0 && (current.bits & requiredMask) == requiredMask)
184 return true;
188 // refill the queue
189 more = false;
190 end += BucketTable.SIZE;
191 for (SubScorer sub = scorers; sub != null; sub = sub.next)
193 Scorer scorer = sub.scorer;
194 while (!sub.done && scorer.Doc() < end)
196 sub.collector.Collect(scorer.Doc(), scorer.Score());
197 sub.done = !scorer.Next();
199 if (!sub.done)
201 more = true;
205 while (bucketTable.first != null || more);
207 return false;
210 public override float Score()
212 if (coordFactors == null)
213 ComputeCoordFactors();
214 return current.score * coordFactors[current.coord];
217 internal sealed class Bucket
219 internal int doc = - 1; // tells if bucket is valid
220 internal float score; // incremental score
221 internal int bits; // used for bool constraints
222 internal int coord; // count of terms in score
223 internal Bucket next; // next valid bucket
226 /// <summary>A simple hash table of document scores within a range. </summary>
227 internal sealed class BucketTable
229 private void InitBlock()
231 buckets = new Bucket[SIZE];
233 public const int SIZE = 1 << 11;
234 public static readonly int MASK;
236 internal Bucket[] buckets;
237 internal Bucket first = null; // head of valid list
239 private BooleanScorer scorer;
241 public BucketTable(BooleanScorer scorer)
243 InitBlock();
244 this.scorer = scorer;
247 public int Size()
249 return SIZE;
252 public HitCollector NewCollector(int mask)
254 return new Collector(mask, this);
256 static BucketTable()
258 MASK = SIZE - 1;
262 internal sealed class Collector : HitCollector
264 private BucketTable bucketTable;
265 private int mask;
266 public Collector(int mask, BucketTable bucketTable)
268 this.mask = mask;
269 this.bucketTable = bucketTable;
271 public override void Collect(int doc, float score)
273 BucketTable table = bucketTable;
274 int i = doc & Lucene.Net.Search.BooleanScorer.BucketTable.MASK;
275 Bucket bucket = table.buckets[i];
276 if (bucket == null)
277 table.buckets[i] = bucket = new Bucket();
279 if (bucket.doc != doc)
281 // invalid bucket
282 bucket.doc = doc; // set doc
283 bucket.score = score; // initialize score
284 bucket.bits = mask; // initialize mask
285 bucket.coord = 1; // initialize coord
287 bucket.next = table.first; // push onto valid list
288 table.first = bucket;
290 else
292 // valid bucket
293 bucket.score += score; // increment score
294 bucket.bits |= mask; // add bits in mask
295 bucket.coord++; // increment coord
300 public override bool SkipTo(int target)
302 throw new System.NotSupportedException();
305 public override Explanation Explain(int doc)
307 throw new System.NotSupportedException();
310 public override System.String ToString()
312 System.Text.StringBuilder buffer = new System.Text.StringBuilder();
313 buffer.Append("boolean(");
314 for (SubScorer sub = scorers; sub != null; sub = sub.next)
316 buffer.Append(sub.scorer.ToString());
317 buffer.Append(" ");
319 buffer.Append(")");
320 return buffer.ToString();