Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
NearSpansUnordered.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using Lucene.Net.Util;
22 using IndexReader = Lucene.Net.Index.IndexReader;
23 
24 namespace Lucene.Net.Search.Spans
25 {
26 
27  /// <summary> Similar to <see cref="NearSpansOrdered" />, but for the unordered case.
28  ///
29  /// Expert:
30  /// Only public for subclassing. Most implementations should not need this class
31  /// </summary>
32  public class NearSpansUnordered : Spans
33  {
34  private SpanNearQuery query;
35 
36  private System.Collections.Generic.IList<SpansCell> ordered = new System.Collections.Generic.List<SpansCell>(); // spans in query order
37  private Spans[] subSpans;
38  private int slop; // from query
39 
40  private SpansCell first; // linked list of spans
41  private SpansCell last; // sorted by doc only
42 
43  private int totalLength; // sum of current lengths
44 
45  private CellQueue queue; // sorted queue of spans
46  private SpansCell max; // max element in queue
47 
48  private bool more = true; // true iff not done
49  private bool firstTime = true; // true before first next()
50 
51  private class CellQueue : PriorityQueue<SpansCell>
52  {
53  private void InitBlock(NearSpansUnordered enclosingInstance)
54  {
55  this.enclosingInstance = enclosingInstance;
56  }
57  private NearSpansUnordered enclosingInstance;
58  public NearSpansUnordered Enclosing_Instance
59  {
60  get
61  {
62  return enclosingInstance;
63  }
64 
65  }
66  public CellQueue(NearSpansUnordered enclosingInstance, int size)
67  {
68  InitBlock(enclosingInstance);
69  Initialize(size);
70  }
71 
72  public override bool LessThan(SpansCell spans1, SpansCell spans2)
73  {
74  if (spans1.Doc() == spans2.Doc())
75  {
76  return NearSpansOrdered.DocSpansOrdered(spans1, spans2);
77  }
78  else
79  {
80  return spans1.Doc() < spans2.Doc();
81  }
82  }
83  }
84 
85 
86  /// <summary>Wraps a Spans, and can be used to form a linked list. </summary>
87  private class SpansCell:Spans
88  {
89  private void InitBlock(NearSpansUnordered enclosingInstance)
90  {
91  this.enclosingInstance = enclosingInstance;
92  }
93  private NearSpansUnordered enclosingInstance;
94  public NearSpansUnordered Enclosing_Instance
95  {
96  get
97  {
98  return enclosingInstance;
99  }
100 
101  }
102  internal /*private*/ Spans spans;
103  internal /*private*/ SpansCell next;
104  private int length = - 1;
105  private int index;
106 
107  public SpansCell(NearSpansUnordered enclosingInstance, Spans spans, int index)
108  {
109  InitBlock(enclosingInstance);
110  this.spans = spans;
111  this.index = index;
112  }
113 
114  public override bool Next()
115  {
116  return Adjust(spans.Next());
117  }
118 
119  public override bool SkipTo(int target)
120  {
121  return Adjust(spans.SkipTo(target));
122  }
123 
124  private bool Adjust(bool condition)
125  {
126  if (length != - 1)
127  {
128  Enclosing_Instance.totalLength -= length; // subtract old length
129  }
130  if (condition)
131  {
132  length = End() - Start();
133  Enclosing_Instance.totalLength += length; // add new length
134 
135  if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc()) && (End() > Enclosing_Instance.max.End()))
136  {
137  Enclosing_Instance.max = this;
138  }
139  }
140  Enclosing_Instance.more = condition;
141  return condition;
142  }
143 
144  public override int Doc()
145  {
146  return spans.Doc();
147  }
148  public override int Start()
149  {
150  return spans.Start();
151  }
152  public override int End()
153  {
154  return spans.End();
155  }
156  // TODO: Remove warning after API has been finalized
157 
158  public override ICollection<byte[]> GetPayload()
159  {
160  return spans.GetPayload().ToArray();
161  }
162 
163  // TODO: Remove warning after API has been finalized
164 
165  public override bool IsPayloadAvailable()
166  {
167  return spans.IsPayloadAvailable();
168  }
169 
170  public override System.String ToString()
171  {
172  return spans.ToString() + "#" + index;
173  }
174  }
175 
176 
178  {
179  this.query = query;
180  this.slop = query.Slop;
181 
182  SpanQuery[] clauses = query.GetClauses();
183  queue = new CellQueue(this, clauses.Length);
184  subSpans = new Spans[clauses.Length];
185  for (int i = 0; i < clauses.Length; i++)
186  {
187  SpansCell cell = new SpansCell(this, clauses[i].GetSpans(reader), i);
188  ordered.Add(cell);
189  subSpans[i] = cell.spans;
190  }
191  }
192  public virtual Spans[] GetSubSpans()
193  {
194  return subSpans;
195  }
196  public override bool Next()
197  {
198  if (firstTime)
199  {
200  InitList(true);
201  ListToQueue(); // initialize queue
202  firstTime = false;
203  }
204  else if (more)
205  {
206  if (Min().Next())
207  {
208  // trigger further scanning
209  queue.UpdateTop(); // maintain queue
210  }
211  else
212  {
213  more = false;
214  }
215  }
216 
217  while (more)
218  {
219 
220  bool queueStale = false;
221 
222  if (Min().Doc() != max.Doc())
223  {
224  // maintain list
225  QueueToList();
226  queueStale = true;
227  }
228 
229  // skip to doc w/ all clauses
230 
231  while (more && first.Doc() < last.Doc())
232  {
233  more = first.SkipTo(last.Doc()); // skip first upto last
234  FirstToLast(); // and move it to the end
235  queueStale = true;
236  }
237 
238  if (!more)
239  return false;
240 
241  // found doc w/ all clauses
242 
243  if (queueStale)
244  {
245  // maintain the queue
246  ListToQueue();
247  queueStale = false;
248  }
249 
250  if (AtMatch())
251  {
252  return true;
253  }
254 
255  more = Min().Next();
256  if (more)
257  {
258  queue.UpdateTop(); // maintain queue
259  }
260  }
261  return false; // no more matches
262  }
263 
264  public override bool SkipTo(int target)
265  {
266  if (firstTime)
267  {
268  // initialize
269  InitList(false);
270  for (SpansCell cell = first; more && cell != null; cell = cell.next)
271  {
272  more = cell.SkipTo(target); // skip all
273  }
274  if (more)
275  {
276  ListToQueue();
277  }
278  firstTime = false;
279  }
280  else
281  {
282  // normal case
283  while (more && Min().Doc() < target)
284  {
285  // skip as needed
286  if (Min().SkipTo(target))
287  {
288  queue.UpdateTop();
289  }
290  else
291  {
292  more = false;
293  }
294  }
295  }
296  return more && (AtMatch() || Next());
297  }
298 
299  private SpansCell Min()
300  {
301  return queue.Top();
302  }
303 
304  public override int Doc()
305  {
306  return Min().Doc();
307  }
308  public override int Start()
309  {
310  return Min().Start();
311  }
312  public override int End()
313  {
314  return max.End();
315  }
316 
317  // TODO: Remove warning after API has been finalized
318 
319  /// <summary> WARNING: The List is not necessarily in order of the the positions</summary>
320  /// <returns> Collection of &amp;lt;c&amp;gt;byte[]&amp;lt;/c&amp;gt; payloads </returns>
321  /// <throws> IOException </throws>
322  public override ICollection<byte[]> GetPayload()
323  {
324  System.Collections.Generic.ISet<byte[]> matchPayload = Lucene.Net.Support.Compatibility.SetFactory.CreateHashSet<byte[]>();
325  for (SpansCell cell = first; cell != null; cell = cell.next)
326  {
327  if (cell.IsPayloadAvailable())
328  {
329  matchPayload.UnionWith(cell.GetPayload());
330  }
331  }
332  return matchPayload;
333  }
334 
335  // TODO: Remove warning after API has been finalized
336 
337  public override bool IsPayloadAvailable()
338  {
339  SpansCell pointer = Min();
340  while (pointer != null)
341  {
342  if (pointer.IsPayloadAvailable())
343  {
344  return true;
345  }
346  pointer = pointer.next;
347  }
348 
349  return false;
350  }
351 
352  public override System.String ToString()
353  {
354  return GetType().FullName + "(" + query.ToString() + ")@" + (firstTime?"START":(more?(Doc() + ":" + Start() + "-" + End()):"END"));
355  }
356 
357  private void InitList(bool next)
358  {
359  for (int i = 0; more && i < ordered.Count; i++)
360  {
361  SpansCell cell = ordered[i];
362  if (next)
363  more = cell.Next(); // move to first entry
364  if (more)
365  {
366  AddToList(cell); // add to list
367  }
368  }
369  }
370 
371  private void AddToList(SpansCell cell)
372  {
373  if (last != null)
374  {
375  // add next to end of list
376  last.next = cell;
377  }
378  else
379  first = cell;
380  last = cell;
381  cell.next = null;
382  }
383 
384  private void FirstToLast()
385  {
386  last.next = first; // move first to end of list
387  last = first;
388  first = first.next;
389  last.next = null;
390  }
391 
392  private void QueueToList()
393  {
394  last = first = null;
395  while (queue.Top() != null)
396  {
397  AddToList(queue.Pop());
398  }
399  }
400 
401  private void ListToQueue()
402  {
403  queue.Clear(); // rebuild queue
404  for (SpansCell cell = first; cell != null; cell = cell.next)
405  {
406  queue.Add(cell); // add to queue from list
407  }
408  }
409 
410  private bool AtMatch()
411  {
412  return (Min().Doc() == max.Doc()) && ((max.End() - Min().Start() - totalLength) <= slop);
413  }
414  }
415 }