NearSpans.cs
上传用户:zhangkuixh
上传日期:2013-09-30
资源大小:5473k
文件大小:10k
源码类别:

搜索引擎

开发平台:

C#

  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.
  15.  */
  16. using System;
  17. using IndexReader = Lucene.Net.Index.IndexReader;
  18. using PriorityQueue = Lucene.Net.Util.PriorityQueue;
  19. namespace Lucene.Net.Search.Spans
  20. {
  21. class NearSpans : Spans
  22. {
  23. private SpanNearQuery query;
  24. private System.Collections.IList ordered = new System.Collections.ArrayList(); // spans in query order
  25. private int slop; // from query
  26. private bool inOrder; // from query
  27. private SpansCell first; // linked list of spans
  28. private SpansCell last; // sorted by doc only
  29. private int totalLength; // sum of current lengths
  30. private CellQueue queue; // sorted queue of spans
  31. private SpansCell max; // max element in queue
  32. private bool more = true; // true iff not done
  33. private bool firstTime = true; // true before first next()
  34. private class CellQueue : PriorityQueue
  35. {
  36. private void  InitBlock(NearSpans enclosingInstance)
  37. {
  38. this.enclosingInstance = enclosingInstance;
  39. }
  40. private NearSpans enclosingInstance;
  41. public NearSpans Enclosing_Instance
  42. {
  43. get
  44. {
  45. return enclosingInstance;
  46. }
  47. }
  48. public CellQueue(NearSpans enclosingInstance, int size)
  49. {
  50. InitBlock(enclosingInstance);
  51. Initialize(size);
  52. }
  53. public override bool LessThan(System.Object o1, System.Object o2)
  54. {
  55. SpansCell spans1 = (SpansCell) o1;
  56. SpansCell spans2 = (SpansCell) o2;
  57. if (spans1.Doc() == spans2.Doc())
  58. {
  59. if (spans1.Start() == spans2.Start())
  60. {
  61. if (spans1.End() == spans2.End())
  62. {
  63. return spans1.index > spans2.index;
  64. }
  65. else
  66. {
  67. return spans1.End() < spans2.End();
  68. }
  69. }
  70. else
  71. {
  72. return spans1.Start() < spans2.Start();
  73. }
  74. }
  75. else
  76. {
  77. return spans1.Doc() < spans2.Doc();
  78. }
  79. }
  80. }
  81. /// <summary>Wraps a Spans, and can be used to form a linked list. </summary>
  82. private class SpansCell : Spans
  83. {
  84. private void  InitBlock(NearSpans enclosingInstance)
  85. {
  86. this.enclosingInstance = enclosingInstance;
  87. }
  88. private NearSpans enclosingInstance;
  89. public NearSpans Enclosing_Instance
  90. {
  91. get
  92. {
  93. return enclosingInstance;
  94. }
  95. }
  96. private Spans spans;
  97. public SpansCell next;
  98. private int length = - 1;
  99. public int index;
  100. public SpansCell(NearSpans enclosingInstance, Spans spans, int index)
  101. {
  102. InitBlock(enclosingInstance);
  103. this.spans = spans;
  104. this.index = index;
  105. }
  106. public virtual bool Next()
  107. {
  108. if (length != - 1)
  109. // subtract old length
  110. Enclosing_Instance.totalLength -= length;
  111. bool more = spans.Next(); // move to next
  112. if (more)
  113. {
  114. length = End() - Start(); // compute new length
  115. Enclosing_Instance.totalLength += length; // add new length to total
  116. if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
  117. Enclosing_Instance.max = this;
  118. }
  119. return more;
  120. }
  121. public virtual bool SkipTo(int target)
  122. {
  123. if (length != - 1)
  124. // subtract old length
  125. Enclosing_Instance.totalLength -= length;
  126. bool more = spans.SkipTo(target); // skip
  127. if (more)
  128. {
  129. length = End() - Start(); // compute new length
  130. Enclosing_Instance.totalLength += length; // add new length to total
  131. if (Enclosing_Instance.max == null || Doc() > Enclosing_Instance.max.Doc() || (Doc() == Enclosing_Instance.max.Doc() && End() > Enclosing_Instance.max.End()))
  132. Enclosing_Instance.max = this;
  133. }
  134. return more;
  135. }
  136. public virtual int Doc()
  137. {
  138. return spans.Doc();
  139. }
  140. public virtual int Start()
  141. {
  142. return spans.Start();
  143. }
  144. public virtual int End()
  145. {
  146. return spans.End();
  147. }
  148. public override System.String ToString()
  149. {
  150. return spans.ToString() + "#" + index;
  151. }
  152. }
  153. public NearSpans(SpanNearQuery query, IndexReader reader)
  154. {
  155. this.query = query;
  156. this.slop = query.GetSlop();
  157. this.inOrder = query.IsInOrder();
  158. SpanQuery[] clauses = query.GetClauses(); // initialize spans & list
  159. queue = new CellQueue(this, clauses.Length);
  160. for (int i = 0; i < clauses.Length; i++)
  161. {
  162. SpansCell cell = new SpansCell(this, clauses[i].GetSpans(reader), i);
  163. ordered.Add(cell); // add to ordered
  164. }
  165. }
  166. public virtual bool Next()
  167. {
  168. if (firstTime)
  169. {
  170. InitList(true);
  171. ListToQueue(); // initialize queue
  172. firstTime = false;
  173. }
  174. else if (more)
  175. {
  176. more = Min().Next(); // trigger further scanning
  177. if (more)
  178. queue.AdjustTop(); // maintain queue
  179. }
  180. while (more)
  181. {
  182. bool queueStale = false;
  183. if (Min().Doc() != max.Doc())
  184. {
  185. // maintain list
  186. QueueToList();
  187. queueStale = true;
  188. }
  189. // skip to doc w/ all clauses
  190. while (more && first.Doc() < last.Doc())
  191. {
  192. more = first.SkipTo(last.Doc()); // skip first upto last
  193. FirstToLast(); // and move it to the end
  194. queueStale = true;
  195. }
  196. if (!more)
  197. return false;
  198. // found doc w/ all clauses
  199. if (queueStale)
  200. {
  201. // maintain the queue
  202. ListToQueue();
  203. queueStale = false;
  204. }
  205. if (AtMatch())
  206. return true;
  207. // trigger further scanning
  208. if (inOrder && CheckSlop())
  209. {
  210. /* There is a non ordered match within slop and an ordered match is needed. */
  211. more = FirstNonOrderedNextToPartialList();
  212. if (more)
  213. {
  214. PartialListToQueue();
  215. }
  216. }
  217. else
  218. {
  219. more = Min().Next();
  220. if (more)
  221. {
  222. queue.AdjustTop(); // maintain queue
  223. }
  224. }
  225. }
  226. return false; // no more matches
  227. }
  228. public virtual bool SkipTo(int target)
  229. {
  230. if (firstTime)
  231. {
  232. // initialize
  233. InitList(false);
  234. for (SpansCell cell = first; more && cell != null; cell = cell.next)
  235. {
  236. more = cell.SkipTo(target); // skip all
  237. }
  238. if (more)
  239. {
  240. ListToQueue();
  241. }
  242. firstTime = false;
  243. }
  244. else
  245. {
  246. // normal case
  247. while (more && Min().Doc() < target)
  248. {
  249. // skip as needed
  250. more = Min().SkipTo(target);
  251. if (more)
  252. queue.AdjustTop();
  253. }
  254. }
  255. if (more)
  256. {
  257. if (AtMatch())
  258. // at a match?
  259. return true;
  260. return Next(); // no, scan
  261. }
  262. return false;
  263. }
  264. private SpansCell Min()
  265. {
  266. return (SpansCell) queue.Top();
  267. }
  268. public virtual int Doc()
  269. {
  270. return Min().Doc();
  271. }
  272. public virtual int Start()
  273. {
  274. return Min().Start();
  275. }
  276. public virtual int End()
  277. {
  278. return max.End();
  279. }
  280. public override System.String ToString()
  281. {
  282. return "spans(" + query.ToString() + ")@" + (firstTime?"START":(more?(Doc() + ":" + Start() + "-" + End()):"END"));
  283. }
  284. private void  InitList(bool next)
  285. {
  286. for (int i = 0; more && i < ordered.Count; i++)
  287. {
  288. SpansCell cell = (SpansCell) ordered[i];
  289. if (next)
  290. more = cell.Next(); // move to first entry
  291. if (more)
  292. {
  293. AddToList(cell); // add to list
  294. }
  295. }
  296. }
  297. private void  AddToList(SpansCell cell)
  298. {
  299. if (last != null)
  300. {
  301. // add next to end of list
  302. last.next = cell;
  303. }
  304. else
  305. first = cell;
  306. last = cell;
  307. cell.next = null;
  308. }
  309. private void  FirstToLast()
  310. {
  311. last.next = first; // move first to end of list
  312. last = first;
  313. first = first.next;
  314. last.next = null;
  315. }
  316. private void  QueueToList()
  317. {
  318. last = first = null;
  319. while (queue.Top() != null)
  320. {
  321. AddToList((SpansCell) queue.Pop());
  322. }
  323. }
  324. private bool FirstNonOrderedNextToPartialList()
  325. {
  326. /* Creates a partial list consisting of first non ordered and earlier.
  327. * Returns first non ordered .next().
  328. */
  329. last = first = null;
  330. int orderedIndex = 0;
  331. while (queue.Top() != null)
  332. {
  333. SpansCell cell = (SpansCell) queue.Pop();
  334. AddToList(cell);
  335. if (cell.index == orderedIndex)
  336. {
  337. orderedIndex++;
  338. }
  339. else
  340. {
  341. return cell.Next();
  342. // FIXME: continue here, rename to eg. checkOrderedMatch():
  343. // when checkSlop() and not ordered, repeat cell.next().
  344. // when checkSlop() and ordered, add to list and repeat queue.pop()
  345. // without checkSlop(): no match, rebuild the queue from the partial list.
  346. // When queue is empty and checkSlop() and ordered there is a match.
  347. }
  348. }
  349. throw new System.SystemException("Unexpected: ordered");
  350. }
  351. private void  ListToQueue()
  352. {
  353. queue.Clear(); // rebuild queue
  354. PartialListToQueue();
  355. }
  356. private void  PartialListToQueue()
  357. {
  358. for (SpansCell cell = first; cell != null; cell = cell.next)
  359. {
  360. queue.Put(cell); // add to queue from list
  361. }
  362. }
  363. private bool AtMatch()
  364. {
  365. return (Min().Doc() == max.Doc()) && CheckSlop() && (!inOrder || MatchIsOrdered());
  366. }
  367. private bool CheckSlop()
  368. {
  369. int matchLength = max.End() - Min().Start();
  370. return (matchLength - totalLength) <= slop;
  371. }
  372. private bool MatchIsOrdered()
  373. {
  374. int lastStart = - 1;
  375. for (int i = 0; i < ordered.Count; i++)
  376. {
  377. int start = ((SpansCell) ordered[i]).Start();
  378. if (!(start > lastStart))
  379. return false;
  380. lastStart = start;
  381. }
  382. return true;
  383. }
  384. }
  385. }