19 using System.Collections.Generic;
22 namespace Lucene.Net.Search.Spans
49 internal class AnonymousClassComparator : System.Collections.IComparer
53 InitBlock(enclosingInstance);
57 this.enclosingInstance = enclosingInstance;
64 return enclosingInstance;
68 public virtual int Compare(System.Object o1, System.Object o2)
73 private void InitBlock()
75 spanDocComparator =
new AnonymousClassComparator(
this);
77 private int allowedSlop;
78 private bool firstTime =
true;
79 private bool more =
false;
82 private Spans[] subSpans;
85 private bool inSameDoc =
false;
87 private int matchDoc = - 1;
88 private int matchStart = - 1;
89 private int matchEnd = - 1;
90 private System.Collections.Generic.List<byte[]> matchPayload;
92 private Spans[] subSpansByDoc;
93 private System.Collections.IComparer spanDocComparator;
96 private bool collectPayloads =
true;
107 throw new System.ArgumentException(
"Less than 2 clauses: " + spanNearQuery);
109 this.collectPayloads = collectPayloads;
110 allowedSlop = spanNearQuery.
Slop;
112 subSpans =
new Spans[clauses.Length];
113 matchPayload =
new System.Collections.Generic.List<byte[]>();
114 subSpansByDoc =
new Spans[clauses.Length];
115 for (
int i = 0; i < clauses.Length; i++)
117 subSpans[i] = clauses[i].
GetSpans(reader);
118 subSpansByDoc[i] = subSpans[i];
120 query = spanNearQuery;
124 public override int Doc()
130 public override int Start()
136 public override int End()
141 public virtual Spans[] GetSubSpans()
149 public override ICollection<byte[]> GetPayload()
156 public override bool IsPayloadAvailable()
158 return (matchPayload.Count == 0) ==
false;
162 public override bool Next()
167 for (
int i = 0; i < subSpans.Length; i++)
169 if (!subSpans[i].Next())
179 matchPayload.Clear();
181 return AdvanceAfterOrdered();
185 public override bool SkipTo(
int target)
190 for (
int i = 0; i < subSpans.Length; i++)
192 if (!subSpans[i].SkipTo(target))
200 else if (more && (subSpans[0].Doc() < target))
202 if (subSpans[0].SkipTo(target))
214 matchPayload.Clear();
216 return AdvanceAfterOrdered();
224 private bool AdvanceAfterOrdered()
226 while (more && (inSameDoc || ToSameDoc()))
228 if (StretchToOrder() && ShrinkToAfterShortestMatch())
238 private bool ToSameDoc()
240 System.Array.Sort(subSpansByDoc, spanDocComparator);
242 int maxDoc = subSpansByDoc[subSpansByDoc.Length - 1].Doc();
243 while (subSpansByDoc[firstIndex].Doc() != maxDoc)
245 if (!subSpansByDoc[firstIndex].SkipTo(maxDoc))
251 maxDoc = subSpansByDoc[firstIndex].Doc();
252 if (++firstIndex == subSpansByDoc.Length)
257 for (
int i = 0; i < subSpansByDoc.Length; i++)
259 System.Diagnostics.Debug.Assert((subSpansByDoc [i].Doc() == maxDoc)
260 ,
"NearSpansOrdered.toSameDoc() spans " + subSpansByDoc [0]
261 +
"\n at doc " + subSpansByDoc [i].Doc()
262 +
", but should be at " + maxDoc);
277 internal static bool DocSpansOrdered(Spans spans1, Spans spans2)
279 System.Diagnostics.Debug.Assert(spans1.Doc() == spans2.Doc(),
"doc1 " + spans1.Doc() +
" != doc2 " + spans2.Doc());
280 int start1 = spans1.Start();
281 int start2 = spans2.Start();
283 return (start1 == start2)?(spans1.End() < spans2.End()):(start1 < start2);
289 private static bool DocSpansOrdered(
int start1,
int end1,
int start2,
int end2)
291 return (start1 == start2)?(end1 < end2):(start1 < start2);
297 private bool StretchToOrder()
299 matchDoc = subSpans[0].Doc();
300 for (
int i = 1; inSameDoc && (i < subSpans.Length); i++)
302 while (!DocSpansOrdered(subSpans[i - 1], subSpans[i]))
304 if (!subSpans[i].Next())
310 else if (matchDoc != subSpans[i].Doc())
324 private bool ShrinkToAfterShortestMatch()
326 matchStart = subSpans[subSpans.Length - 1].Start();
327 matchEnd = subSpans[subSpans.Length - 1].End();
328 System.Collections.Generic.Dictionary<byte[], byte[]> possibleMatchPayloads =
new System.Collections.Generic.Dictionary<byte[], byte[]>();
329 if (subSpans[subSpans.Length - 1].IsPayloadAvailable())
331 System.Collections.Generic.ICollection<byte[]> payload = subSpans[subSpans.Length - 1].GetPayload();
332 foreach(byte[] pl
in payload)
334 if (!possibleMatchPayloads.ContainsKey(pl))
336 possibleMatchPayloads.Add(pl, pl);
341 System.Collections.Generic.List<byte[]> possiblePayload = null;
344 int lastStart = matchStart;
345 int lastEnd = matchEnd;
346 for (
int i = subSpans.Length - 2; i >= 0; i--)
348 Spans prevSpans = subSpans[i];
349 if (collectPayloads && prevSpans.IsPayloadAvailable())
351 System.Collections.Generic.ICollection<byte[]> payload = prevSpans.GetPayload();
352 possiblePayload =
new System.Collections.Generic.List<byte[]>(payload.Count);
353 possiblePayload.AddRange(payload);
356 int prevStart = prevSpans.Start();
357 int prevEnd = prevSpans.End();
361 if (!prevSpans.Next())
367 else if (matchDoc != prevSpans.Doc())
374 int ppStart = prevSpans.Start();
375 int ppEnd = prevSpans.End();
376 if (!DocSpansOrdered(ppStart, ppEnd, lastStart, lastEnd))
385 if (collectPayloads && prevSpans.IsPayloadAvailable())
387 System.Collections.Generic.ICollection<byte[]> payload = prevSpans.GetPayload();
388 possiblePayload =
new System.Collections.Generic.List<byte[]>(payload.Count);
389 possiblePayload.AddRange(payload);
395 if (collectPayloads && possiblePayload != null)
397 foreach (byte[] pl
in possiblePayload)
399 if (!possibleMatchPayloads.ContainsKey(pl))
401 possibleMatchPayloads.Add(pl, pl);
406 System.Diagnostics.Debug.Assert(prevStart <= matchStart);
407 if (matchStart > prevEnd)
410 matchSlop += (matchStart - prevEnd);
416 matchStart = prevStart;
417 lastStart = prevStart;
421 bool match = matchSlop <= allowedSlop;
423 if (collectPayloads && match && possibleMatchPayloads.Count > 0)
425 matchPayload.AddRange(possibleMatchPayloads.Keys);
431 public override System.String ToString()
433 return GetType().FullName +
"(" + query.ToString() +
")@" + (firstTime?
"START":(more?(Doc() +
":" + Start() +
"-" + End()):
"END"));