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.
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
52 return enclosingInstance
;
56 public CellQueue(NearSpans enclosingInstance
, int size
)
58 InitBlock(enclosingInstance
);
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
;
76 return spans1
.End() < spans2
.End();
81 return spans1
.Start() < spans2
.Start();
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
;
110 public SpansCell next
;
111 private int length
= - 1;
114 public SpansCell(NearSpans enclosingInstance
, Spans spans
, int index
)
116 InitBlock(enclosingInstance
);
121 public virtual bool Next()
124 // subtract old length
125 Enclosing_Instance
.totalLength
-= length
;
127 bool more
= spans
.Next(); // move to next
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;
141 public virtual bool SkipTo(int target
)
144 // subtract old length
145 Enclosing_Instance
.totalLength
-= length
;
147 bool more
= spans
.SkipTo(target
); // skip
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;
161 public virtual int Doc()
165 public virtual int Start()
167 return spans
.Start();
169 public virtual int End()
174 public override System
.String
ToString()
176 return spans
.ToString() + "#" + index
;
180 public NearSpans(SpanNearQuery query
, IndexReader reader
)
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()
200 ListToQueue(); // initialize queue
205 more
= Min().Next(); // trigger further scanning
207 queue
.AdjustTop(); // maintain queue
213 bool queueStale
= false;
215 if (Min().Doc() != max
.Doc())
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
234 // found doc w/ all clauses
238 // maintain the queue
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();
253 PartialListToQueue();
261 queue
.AdjustTop(); // maintain queue
265 return false; // no more matches
268 public virtual bool SkipTo(int target
)
274 for (SpansCell cell
= first
; more
&& cell
!= null; cell
= cell
.next
)
276 more
= cell
.SkipTo(target
); // skip all
287 while (more
&& Min().Doc() < target
)
290 more
= Min().SkipTo(target
);
302 return Next(); // no, scan
308 private SpansCell
Min()
310 return (SpansCell
) queue
.Top();
313 public virtual int Doc()
317 public virtual int Start()
319 return Min().Start();
321 public virtual int 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
];
338 more
= cell
.Next(); // move to first entry
341 AddToList(cell
); // add to list
346 private void AddToList(SpansCell cell
)
350 // add next to end of list
359 private void FirstToLast()
361 last
.next
= first
; // move first to end of list
367 private void QueueToList()
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().
382 int orderedIndex
= 0;
383 while (queue
.Top() != null)
385 SpansCell cell
= (SpansCell
) queue
.Pop();
387 if (cell
.index
== orderedIndex
)
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()
432 for (int i
= 0; i
< ordered
.Count
; i
++)
434 int start
= ((SpansCell
) ordered
[i
]).Start();
435 if (!(start
> lastStart
))