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

搜索引擎

开发平台:

C#

  1. /*
  2.  * Copyright 2005 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 PriorityQueue = Lucene.Net.Util.PriorityQueue;
  18. namespace Lucene.Net.Search
  19. {
  20. /// <summary>A Scorer for OR like queries, counterpart of Lucene's <code>ConjunctionScorer</code>.
  21. /// This Scorer implements {@link Scorer#SkipTo(int)} and uses skipTo() on the given Scorers. 
  22. /// </summary>
  23. public class DisjunctionSumScorer : Scorer
  24. {
  25. /// <summary>The number of subscorers. </summary>
  26. private int nrScorers;
  27. /// <summary>The subscorers. </summary>
  28. protected internal System.Collections.IList subScorers;
  29. /// <summary>The minimum number of scorers that should match. </summary>
  30. private int minimumNrMatchers;
  31. /// <summary>The scorerQueue contains all subscorers ordered by their current doc(),
  32. /// with the minimum at the top.
  33. /// <br>The scorerQueue is initialized the first time next() or skipTo() is called.
  34. /// <br>An exhausted scorer is immediately removed from the scorerQueue.
  35. /// <br>If less than the minimumNrMatchers scorers
  36. /// remain in the scorerQueue next() and skipTo() return false.
  37. /// <p>
  38. /// After each to call to next() or skipTo()
  39. /// <code>currentSumScore</code> is the total score of the current matching doc,
  40. /// <code>nrMatchers</code> is the number of matching scorers,
  41. /// and all scorers are after the matching doc, or are exhausted.
  42. /// </summary>
  43. private ScorerQueue scorerQueue = null;
  44. /// <summary>The document number of the current match. </summary>
  45. private int currentDoc = - 1;
  46. /// <summary>The number of subscorers that provide the current match. </summary>
  47. protected internal int nrMatchers = - 1;
  48. private float currentScore = System.Single.NaN;
  49. /// <summary>Construct a <code>DisjunctionScorer</code>.</summary>
  50. /// <param name="subScorers">A collection of at least two subscorers.
  51. /// </param>
  52. /// <param name="minimumNrMatchers">The positive minimum number of subscorers that should
  53. /// match to match this query.
  54. /// <br>When <code>minimumNrMatchers</code> is bigger than
  55. /// the number of <code>subScorers</code>,
  56. /// no matches will be produced.
  57. /// <br>When minimumNrMatchers equals the number of subScorers,
  58. /// it more efficient to use <code>ConjunctionScorer</code>.
  59. /// </param>
  60. public DisjunctionSumScorer(System.Collections.IList subScorers, int minimumNrMatchers) : base(null)
  61. {
  62. nrScorers = subScorers.Count;
  63. if (minimumNrMatchers <= 0)
  64. {
  65. throw new System.ArgumentException("Minimum nr of matchers must be positive");
  66. }
  67. if (nrScorers <= 1)
  68. {
  69. throw new System.ArgumentException("There must be at least 2 subScorers");
  70. }
  71. this.minimumNrMatchers = minimumNrMatchers;
  72. this.subScorers = subScorers;
  73. }
  74. /// <summary>Construct a <code>DisjunctionScorer</code>, using one as the minimum number
  75. /// of matching subscorers.
  76. /// </summary>
  77. public DisjunctionSumScorer(System.Collections.IList subScorers) : this(subScorers, 1)
  78. {
  79. }
  80. /// <summary>Called the first time next() or skipTo() is called to
  81. /// initialize <code>scorerQueue</code>.
  82. /// </summary>
  83. private void  InitScorerQueue()
  84. {
  85. System.Collections.IEnumerator si = subScorers.GetEnumerator();
  86. scorerQueue = new ScorerQueue(this, nrScorers);
  87. while (si.MoveNext())
  88. {
  89. Scorer se = (Scorer) si.Current;
  90. if (se.Next())
  91. {
  92. // doc() method will be used in scorerQueue.
  93. scorerQueue.Insert(se);
  94. }
  95. }
  96. }
  97. /// <summary>A <code>PriorityQueue</code> that orders by {@link Scorer#Doc()}. </summary>
  98. private class ScorerQueue : PriorityQueue
  99. {
  100. private void  InitBlock(DisjunctionSumScorer enclosingInstance)
  101. {
  102. this.enclosingInstance = enclosingInstance;
  103. }
  104. private DisjunctionSumScorer enclosingInstance;
  105. public DisjunctionSumScorer Enclosing_Instance
  106. {
  107. get
  108. {
  109. return enclosingInstance;
  110. }
  111. }
  112. internal ScorerQueue(DisjunctionSumScorer enclosingInstance, int size)
  113. {
  114. InitBlock(enclosingInstance);
  115. Initialize(size);
  116. }
  117. public override bool LessThan(System.Object o1, System.Object o2)
  118. {
  119. return ((Scorer) o1).Doc() < ((Scorer) o2).Doc();
  120. }
  121. }
  122. public override bool Next()
  123. {
  124. if (scorerQueue == null)
  125. {
  126. InitScorerQueue();
  127. }
  128. if (scorerQueue.Size() < minimumNrMatchers)
  129. {
  130. return false;
  131. }
  132. else
  133. {
  134. return AdvanceAfterCurrent();
  135. }
  136. }
  137. /// <summary>Advance all subscorers after the current document determined by the
  138. /// top of the <code>scorerQueue</code>.
  139. /// Repeat until at least the minimum number of subscorers match on the same
  140. /// document and all subscorers are after that document or are exhausted.
  141. /// <br>On entry the <code>scorerQueue</code> has at least <code>minimumNrMatchers</code>
  142. /// available. At least the scorer with the minimum document number will be advanced.
  143. /// </summary>
  144. /// <returns> true iff there is a match.
  145. /// <br>In case there is a match, </code>currentDoc</code>, </code>currentSumScore</code>,
  146. /// and </code>nrMatchers</code> describe the match.
  147. /// 
  148. /// </returns>
  149. /// <todo>  Investigate whether it is possible to use skipTo() when </todo>
  150. /// <summary> the minimum number of matchers is bigger than one, ie. try and use the
  151. /// character of ConjunctionScorer for the minimum number of matchers.
  152. /// </summary>
  153. protected internal virtual bool AdvanceAfterCurrent()
  154. {
  155. do 
  156. {
  157. // repeat until minimum nr of matchers
  158. Scorer top = (Scorer) scorerQueue.Top();
  159. currentDoc = top.Doc();
  160. currentScore = top.Score();
  161. nrMatchers = 1;
  162. do 
  163. {
  164. // Until all subscorers are after currentDoc
  165. if (top.Next())
  166. {
  167. scorerQueue.AdjustTop();
  168. }
  169. else
  170. {
  171. scorerQueue.Pop();
  172. if (scorerQueue.Size() < (minimumNrMatchers - nrMatchers))
  173. {
  174. // Not enough subscorers left for a match on this document,
  175. // and also no more chance of any further match.
  176. return false;
  177. }
  178. if (scorerQueue.Size() == 0)
  179. {
  180. break; // nothing more to advance, check for last match.
  181. }
  182. }
  183. top = (Scorer) scorerQueue.Top();
  184. if (top.Doc() != currentDoc)
  185. {
  186. break; // All remaining subscorers are after currentDoc.
  187. }
  188. else
  189. {
  190. currentScore += top.Score();
  191. nrMatchers++;
  192. }
  193. }
  194. while (true);
  195. if (nrMatchers >= minimumNrMatchers)
  196. {
  197. return true;
  198. }
  199. else if (scorerQueue.Size() < minimumNrMatchers)
  200. {
  201. return false;
  202. }
  203. }
  204. while (true);
  205. }
  206. /// <summary>Returns the score of the current document matching the query.
  207. /// Initially invalid, until {@link #Next()} is called the first time.
  208. /// </summary>
  209. public override float Score()
  210. {
  211. return currentScore;
  212. }
  213. public override int Doc()
  214. {
  215. return currentDoc;
  216. }
  217. /// <summary>Returns the number of subscorers matching the current document.
  218. /// Initially invalid, until {@link #Next()} is called the first time.
  219. /// </summary>
  220. public virtual int NrMatchers()
  221. {
  222. return nrMatchers;
  223. }
  224. /// <summary>Skips to the first match beyond the current whose document number is
  225. /// greater than or equal to a given target.
  226. /// <br>When this method is used the {@link #Explain(int)} method should not be used.
  227. /// <br>The implementation uses the skipTo() method on the subscorers.
  228. /// </summary>
  229. /// <param name="target">The target document number.
  230. /// </param>
  231. /// <returns> true iff there is such a match.
  232. /// </returns>
  233. public override bool SkipTo(int target)
  234. {
  235. if (scorerQueue == null)
  236. {
  237. InitScorerQueue();
  238. }
  239. if (scorerQueue.Size() < minimumNrMatchers)
  240. {
  241. return false;
  242. }
  243. if (target <= currentDoc)
  244. {
  245. target = currentDoc + 1;
  246. }
  247. do 
  248. {
  249. Scorer top = (Scorer) scorerQueue.Top();
  250. if (top.Doc() >= target)
  251. {
  252. return AdvanceAfterCurrent();
  253. }
  254. else if (top.SkipTo(target))
  255. {
  256. scorerQueue.AdjustTop();
  257. }
  258. else
  259. {
  260. scorerQueue.Pop();
  261. if (scorerQueue.Size() < minimumNrMatchers)
  262. {
  263. return false;
  264. }
  265. }
  266. }
  267. while (true);
  268. }
  269. /// <summary>Gives and explanation for the score of a given document.</summary>
  270. /// <todo>  Show the resulting score. See BooleanScorer.explain() on how to do this. </todo>
  271. public override Explanation Explain(int doc)
  272. {
  273. Explanation res = new Explanation();
  274. res.SetDescription("At least " + minimumNrMatchers + " of");
  275. System.Collections.IEnumerator ssi = subScorers.GetEnumerator();
  276. while (ssi.MoveNext())
  277. {
  278. res.AddDetail(((Scorer) ssi.Current).Explain(doc));
  279. }
  280. return res;
  281. }
  282. }
  283. }