2 * Copyright 2004 The Apache Software Foundation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
54 return enclosingInstance
;
58 public CellQueue(NearSpans enclosingInstance
, int size
)
60 InitBlock(enclosingInstance
);
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
;
78 return spans1
.End() < spans2
.End();
83 return spans1
.Start() < spans2
.Start();
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
;
111 public SpansCell next
;
112 private int length
= - 1;
115 public SpansCell(NearSpans enclosingInstance
, Spans spans
, int index
)
117 InitBlock(enclosingInstance
);
122 public virtual bool Next()
125 // subtract old length
126 Enclosing_Instance
.totalLength
-= length
;
128 bool more
= spans
.Next(); // move to next
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;
142 public virtual bool SkipTo(int target
)
145 // subtract old length
146 Enclosing_Instance
.totalLength
-= length
;
148 bool more
= spans
.SkipTo(target
); // skip
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;
162 public virtual int Doc()
166 public virtual int Start()
168 return spans
.Start();
170 public virtual int End()
175 public override System
.String
ToString()
177 return spans
.ToString() + "#" + index
;
181 public NearSpans(SpanNearQuery query
, IndexReader reader
)
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()
201 ListToQueue(); // initialize queue
206 more
= Min().Next(); // trigger further scanning
208 queue
.AdjustTop(); // maintain queue
214 bool queueStale
= false;
216 if (Min().Doc() != max
.Doc())
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
235 // found doc w/ all clauses
239 // maintain the queue
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();
254 PartialListToQueue();
262 queue
.AdjustTop(); // maintain queue
266 return false; // no more matches
269 public virtual bool SkipTo(int target
)
275 for (SpansCell cell
= first
; more
&& cell
!= null; cell
= cell
.next
)
277 more
= cell
.SkipTo(target
); // skip all
288 while (more
&& Min().Doc() < target
)
291 more
= Min().SkipTo(target
);
303 return Next(); // no, scan
309 private SpansCell
Min()
311 return (SpansCell
) queue
.Top();
314 public virtual int Doc()
318 public virtual int Start()
320 return Min().Start();
322 public virtual int 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
];
339 more
= cell
.Next(); // move to first entry
342 AddToList(cell
); // add to list
347 private void AddToList(SpansCell cell
)
351 // add next to end of list
360 private void FirstToLast()
362 last
.next
= first
; // move first to end of list
368 private void QueueToList()
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().
383 int orderedIndex
= 0;
384 while (queue
.Top() != null)
386 SpansCell cell
= (SpansCell
) queue
.Pop();
388 if (cell
.index
== orderedIndex
)
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()
433 for (int i
= 0; i
< ordered
.Count
; i
++)
435 int start
= ((SpansCell
) ordered
[i
]).Start();
436 if (!(start
> lastStart
))