cvsimport
[beagle.git] / beagled / Lucene.Net / Search / Spans / NearSpans.cs
blob867cebcce55ba8a1c270a5c0a674af43769994a1
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.
17 using System;
18 using IndexReader = Lucene.Net.Index.IndexReader;
19 using PriorityQueue = Lucene.Net.Util.PriorityQueue;
21 namespace Lucene.Net.Search.Spans
24 class NearSpans : Spans
26 private SpanNearQuery query;
28 private System.Collections.IList ordered = new System.Collections.ArrayList(); // spans in query order
29 private int slop; // from query
30 private bool inOrder; // from query
32 private SpansCell first; // linked list of spans
33 private SpansCell last; // sorted by doc only
35 private int totalLength; // sum of current lengths
37 private CellQueue queue; // sorted queue of spans
38 private SpansCell max; // max element in queue
40 private bool more = true; // true iff not done
41 private bool firstTime = true; // true before first next()
43 private class CellQueue : PriorityQueue
45 private void InitBlock(NearSpans enclosingInstance)
47 this.enclosingInstance = enclosingInstance;
49 private NearSpans enclosingInstance;
50 public NearSpans Enclosing_Instance
52 get
54 return enclosingInstance;
58 public CellQueue(NearSpans enclosingInstance, int size)
60 InitBlock(enclosingInstance);
61 Initialize(size);
64 public override bool LessThan(System.Object o1, System.Object o2)
66 SpansCell spans1 = (SpansCell) o1;
67 SpansCell spans2 = (SpansCell) o2;
68 if (spans1.Doc() == spans2.Doc())
70 if (spans1.Start() == spans2.Start())
72 if (spans1.End() == spans2.End())
74 return spans1.index > spans2.index;
76 else
78 return spans1.End() < spans2.End();
81 else
83 return spans1.Start() < spans2.Start();
86 else
88 return spans1.Doc() < spans2.Doc();
94 /// <summary>Wraps a Spans, and can be used to form a linked list. </summary>
95 private class SpansCell : Spans
97 private void InitBlock(NearSpans enclosingInstance)
99 this.enclosingInstance = enclosingInstance;
101 private NearSpans enclosingInstance;
102 public NearSpans Enclosing_Instance
106 return enclosingInstance;
110 private Spans spans;
111 public SpansCell next;
112 private int length = - 1;
113 public int index;
115 public SpansCell(NearSpans enclosingInstance, Spans spans, int index)
117 InitBlock(enclosingInstance);
118 this.spans = spans;
119 this.index = index;
122 public virtual bool Next()
124 if (length != - 1)
125 // subtract old length
126 Enclosing_Instance.totalLength -= length;
128 bool more = spans.Next(); // move to next
130 if (more)
132 length = End() - Start(); // compute new length
133 Enclosing_Instance.totalLength += length; // add new length to total
135 if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
136 Enclosing_Instance.max = this;
139 return more;
142 public virtual bool SkipTo(int target)
144 if (length != - 1)
145 // subtract old length
146 Enclosing_Instance.totalLength -= length;
148 bool more = spans.SkipTo(target); // skip
150 if (more)
152 length = End() - Start(); // compute new length
153 Enclosing_Instance.totalLength += length; // add new length to total
155 if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
156 Enclosing_Instance.max = this;
159 return more;
162 public virtual int Doc()
164 return spans.Doc();
166 public virtual int Start()
168 return spans.Start();
170 public virtual int End()
172 return spans.End();
175 public override System.String ToString()
177 return spans.ToString() + "#" + index;
181 public NearSpans(SpanNearQuery query, IndexReader reader)
183 this.query = query;
184 this.slop = query.GetSlop();
185 this.inOrder = query.IsInOrder();
187 SpanQuery[] clauses = query.GetClauses(); // initialize spans & list
188 queue = new CellQueue(this, clauses.Length);
189 for (int i = 0; i < clauses.Length; i++)
191 SpansCell cell = new SpansCell(this, clauses[i].GetSpans(reader), i);
192 ordered.Add(cell); // add to ordered
196 public virtual bool Next()
198 if (firstTime)
200 InitList(true);
201 ListToQueue(); // initialize queue
202 firstTime = false;
204 else if (more)
206 more = Min().Next(); // trigger further scanning
207 if (more)
208 queue.AdjustTop(); // maintain queue
211 while (more)
214 bool queueStale = false;
216 if (Min().Doc() != max.Doc())
218 // maintain list
219 QueueToList();
220 queueStale = true;
223 // skip to doc w/ all clauses
225 while (more && first.Doc() < last.Doc())
227 more = first.SkipTo(last.Doc()); // skip first upto last
228 FirstToLast(); // and move it to the end
229 queueStale = true;
232 if (!more)
233 return false;
235 // found doc w/ all clauses
237 if (queueStale)
239 // maintain the queue
240 ListToQueue();
241 queueStale = false;
244 if (AtMatch())
245 return true;
247 // trigger further scanning
248 if (inOrder && CheckSlop())
250 /* There is a non ordered match within slop and an ordered match is needed. */
251 more = FirstNonOrderedNextToPartialList();
252 if (more)
254 PartialListToQueue();
257 else
259 more = Min().Next();
260 if (more)
262 queue.AdjustTop(); // maintain queue
266 return false; // no more matches
269 public virtual bool SkipTo(int target)
271 if (firstTime)
273 // initialize
274 InitList(false);
275 for (SpansCell cell = first; more && cell != null; cell = cell.next)
277 more = cell.SkipTo(target); // skip all
279 if (more)
281 ListToQueue();
283 firstTime = false;
285 else
287 // normal case
288 while (more && Min().Doc() < target)
290 // skip as needed
291 more = Min().SkipTo(target);
292 if (more)
293 queue.AdjustTop();
296 if (more)
299 if (AtMatch())
300 // at a match?
301 return true;
303 return Next(); // no, scan
306 return false;
309 private SpansCell Min()
311 return (SpansCell) queue.Top();
314 public virtual int Doc()
316 return Min().Doc();
318 public virtual int Start()
320 return Min().Start();
322 public virtual int End()
324 return max.End();
328 public override System.String ToString()
330 return "spans(" + query.ToString() + ")@" + (firstTime?"START":(more?(Doc() + ":" + Start() + "-" + End()):"END"));
333 private void InitList(bool next)
335 for (int i = 0; more && i < ordered.Count; i++)
337 SpansCell cell = (SpansCell) ordered[i];
338 if (next)
339 more = cell.Next(); // move to first entry
340 if (more)
342 AddToList(cell); // add to list
347 private void AddToList(SpansCell cell)
349 if (last != null)
351 // add next to end of list
352 last.next = cell;
354 else
355 first = cell;
356 last = cell;
357 cell.next = null;
360 private void FirstToLast()
362 last.next = first; // move first to end of list
363 last = first;
364 first = first.next;
365 last.next = null;
368 private void QueueToList()
370 last = first = null;
371 while (queue.Top() != null)
373 AddToList((SpansCell) queue.Pop());
377 private bool FirstNonOrderedNextToPartialList()
379 /* Creates a partial list consisting of first non ordered and earlier.
380 * Returns first non ordered .next().
382 last = first = null;
383 int orderedIndex = 0;
384 while (queue.Top() != null)
386 SpansCell cell = (SpansCell) queue.Pop();
387 AddToList(cell);
388 if (cell.index == orderedIndex)
390 orderedIndex++;
392 else
394 return cell.Next();
395 // FIXME: continue here, rename to eg. checkOrderedMatch():
396 // when checkSlop() and not ordered, repeat cell.next().
397 // when checkSlop() and ordered, add to list and repeat queue.pop()
398 // without checkSlop(): no match, rebuild the queue from the partial list.
399 // When queue is empty and checkSlop() and ordered there is a match.
402 throw new System.SystemException("Unexpected: ordered");
405 private void ListToQueue()
407 queue.Clear(); // rebuild queue
408 PartialListToQueue();
411 private void PartialListToQueue()
413 for (SpansCell cell = first; cell != null; cell = cell.next)
415 queue.Put(cell); // add to queue from list
419 private bool AtMatch()
421 return (Min().Doc() == max.Doc()) && CheckSlop() && (!inOrder || MatchIsOrdered());
424 private bool CheckSlop()
426 int matchLength = max.End() - Min().Start();
427 return (matchLength - totalLength) <= slop;
430 private bool MatchIsOrdered()
432 int lastStart = - 1;
433 for (int i = 0; i < ordered.Count; i++)
435 int start = ((SpansCell) ordered[i]).Start();
436 if (!(start > lastStart))
437 return false;
438 lastStart = start;
440 return true;