Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / beagled / Lucene.Net / Search / Spans / NearSpans.cs
blob796bc4654e5bf775e2dc988f6c0a97ced446812e
1 /*
2 * Copyright 2004 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.
16 using System;
17 using IndexReader = Lucene.Net.Index.IndexReader;
18 using PriorityQueue = Lucene.Net.Util.PriorityQueue;
19 namespace Lucene.Net.Search.Spans
22 class NearSpans : Spans
24 private SpanNearQuery query;
26 private System.Collections.IList ordered = new System.Collections.ArrayList(); // spans in query order
27 private int slop; // from query
28 private bool inOrder; // from query
30 private SpansCell first; // linked list of spans
31 private SpansCell last; // sorted by doc only
33 private int totalLength; // sum of current lengths
35 private CellQueue queue; // sorted queue of spans
36 private SpansCell max; // max element in queue
38 private bool more = true; // true iff not done
39 private bool firstTime = true; // true before first next()
41 private class CellQueue : PriorityQueue
43 private void InitBlock(NearSpans enclosingInstance)
45 this.enclosingInstance = enclosingInstance;
47 private NearSpans enclosingInstance;
48 public NearSpans Enclosing_Instance
50 get
52 return enclosingInstance;
56 public CellQueue(NearSpans enclosingInstance, int size)
58 InitBlock(enclosingInstance);
59 Initialize(size);
62 public override bool LessThan(System.Object o1, System.Object o2)
64 SpansCell spans1 = (SpansCell) o1;
65 SpansCell spans2 = (SpansCell) o2;
66 if (spans1.Doc() == spans2.Doc())
68 if (spans1.Start() == spans2.Start())
70 if (spans1.End() == spans2.End())
72 return spans1.index > spans2.index;
74 else
76 return spans1.End() < spans2.End();
79 else
81 return spans1.Start() < spans2.Start();
84 else
86 return spans1.Doc() < spans2.Doc();
92 /// <summary>Wraps a Spans, and can be used to form a linked list. </summary>
93 private class SpansCell : Spans
95 private void InitBlock(NearSpans enclosingInstance)
97 this.enclosingInstance = enclosingInstance;
99 private NearSpans enclosingInstance;
100 public NearSpans Enclosing_Instance
104 return enclosingInstance;
109 private Spans spans;
110 public SpansCell next;
111 private int length = - 1;
112 public int index;
114 public SpansCell(NearSpans enclosingInstance, Spans spans, int index)
116 InitBlock(enclosingInstance);
117 this.spans = spans;
118 this.index = index;
121 public virtual bool Next()
123 if (length != - 1)
124 // subtract old length
125 Enclosing_Instance.totalLength -= length;
127 bool more = spans.Next(); // move to next
129 if (more)
131 length = End() - Start(); // compute new length
132 Enclosing_Instance.totalLength += length; // add new length to total
134 if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
135 Enclosing_Instance.max = this;
138 return more;
141 public virtual bool SkipTo(int target)
143 if (length != - 1)
144 // subtract old length
145 Enclosing_Instance.totalLength -= length;
147 bool more = spans.SkipTo(target); // skip
149 if (more)
151 length = End() - Start(); // compute new length
152 Enclosing_Instance.totalLength += length; // add new length to total
154 if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
155 Enclosing_Instance.max = this;
158 return more;
161 public virtual int Doc()
163 return spans.Doc();
165 public virtual int Start()
167 return spans.Start();
169 public virtual int End()
171 return spans.End();
174 public override System.String ToString()
176 return spans.ToString() + "#" + index;
180 public NearSpans(SpanNearQuery query, IndexReader reader)
182 this.query = query;
183 this.slop = query.GetSlop();
184 this.inOrder = query.IsInOrder();
186 SpanQuery[] clauses = query.GetClauses(); // initialize spans & list
187 queue = new CellQueue(this, clauses.Length);
188 for (int i = 0; i < clauses.Length; i++)
190 SpansCell cell = new SpansCell(this, clauses[i].GetSpans(reader), i);
191 ordered.Add(cell); // add to ordered
195 public virtual bool Next()
197 if (firstTime)
199 InitList(true);
200 ListToQueue(); // initialize queue
201 firstTime = false;
203 else if (more)
205 more = Min().Next(); // trigger further scanning
206 if (more)
207 queue.AdjustTop(); // maintain queue
210 while (more)
213 bool queueStale = false;
215 if (Min().Doc() != max.Doc())
217 // maintain list
218 QueueToList();
219 queueStale = true;
222 // skip to doc w/ all clauses
224 while (more && first.Doc() < last.Doc())
226 more = first.SkipTo(last.Doc()); // skip first upto last
227 FirstToLast(); // and move it to the end
228 queueStale = true;
231 if (!more)
232 return false;
234 // found doc w/ all clauses
236 if (queueStale)
238 // maintain the queue
239 ListToQueue();
240 queueStale = false;
243 if (AtMatch())
244 return true;
246 // trigger further scanning
247 if (inOrder && CheckSlop())
249 /* There is a non ordered match within slop and an ordered match is needed. */
250 more = FirstNonOrderedNextToPartialList();
251 if (more)
253 PartialListToQueue();
256 else
258 more = Min().Next();
259 if (more)
261 queue.AdjustTop(); // maintain queue
265 return false; // no more matches
268 public virtual bool SkipTo(int target)
270 if (firstTime)
272 // initialize
273 InitList(false);
274 for (SpansCell cell = first; more && cell != null; cell = cell.next)
276 more = cell.SkipTo(target); // skip all
278 if (more)
280 ListToQueue();
282 firstTime = false;
284 else
286 // normal case
287 while (more && Min().Doc() < target)
289 // skip as needed
290 more = Min().SkipTo(target);
291 if (more)
292 queue.AdjustTop();
295 if (more)
298 if (AtMatch())
299 // at a match?
300 return true;
302 return Next(); // no, scan
305 return false;
308 private SpansCell Min()
310 return (SpansCell) queue.Top();
313 public virtual int Doc()
315 return Min().Doc();
317 public virtual int Start()
319 return Min().Start();
321 public virtual int End()
323 return max.End();
327 public override System.String ToString()
329 return "spans(" + query.ToString() + ")@" + (firstTime?"START":(more?(Doc() + ":" + Start() + "-" + End()):"END"));
332 private void InitList(bool next)
334 for (int i = 0; more && i < ordered.Count; i++)
336 SpansCell cell = (SpansCell) ordered[i];
337 if (next)
338 more = cell.Next(); // move to first entry
339 if (more)
341 AddToList(cell); // add to list
346 private void AddToList(SpansCell cell)
348 if (last != null)
350 // add next to end of list
351 last.next = cell;
353 else
354 first = cell;
355 last = cell;
356 cell.next = null;
359 private void FirstToLast()
361 last.next = first; // move first to end of list
362 last = first;
363 first = first.next;
364 last.next = null;
367 private void QueueToList()
369 last = first = null;
370 while (queue.Top() != null)
372 AddToList((SpansCell) queue.Pop());
376 private bool FirstNonOrderedNextToPartialList()
378 /* Creates a partial list consisting of first non ordered and earlier.
379 * Returns first non ordered .next().
381 last = first = null;
382 int orderedIndex = 0;
383 while (queue.Top() != null)
385 SpansCell cell = (SpansCell) queue.Pop();
386 AddToList(cell);
387 if (cell.index == orderedIndex)
389 orderedIndex++;
391 else
393 return cell.Next();
394 // FIXME: continue here, rename to eg. checkOrderedMatch():
395 // when checkSlop() and not ordered, repeat cell.next().
396 // when checkSlop() and ordered, add to list and repeat queue.pop()
397 // without checkSlop(): no match, rebuild the queue from the partial list.
398 // When queue is empty and checkSlop() and ordered there is a match.
401 throw new System.SystemException("Unexpected: ordered");
404 private void ListToQueue()
406 queue.Clear(); // rebuild queue
407 PartialListToQueue();
410 private void PartialListToQueue()
412 for (SpansCell cell = first; cell != null; cell = cell.next)
414 queue.Put(cell); // add to queue from list
418 private bool AtMatch()
420 return (Min().Doc() == max.Doc()) && CheckSlop() && (!inOrder || MatchIsOrdered());
423 private bool CheckSlop()
425 int matchLength = max.End() - Min().Start();
426 return (matchLength - totalLength) <= slop;
429 private bool MatchIsOrdered()
431 int lastStart = - 1;
432 for (int i = 0; i < ordered.Count; i++)
434 int start = ((SpansCell) ordered[i]).Start();
435 if (!(start > lastStart))
436 return false;
437 lastStart = start;
439 return true;