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

搜索引擎

开发平台:

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 Term = Lucene.Net.Index.Term;
  18. using PriorityQueue = Lucene.Net.Util.PriorityQueue;
  19. namespace Lucene.Net.Search
  20. {
  21. /// <summary>Implements parallel search over a set of <code>Searchables</code>.
  22. /// 
  23. /// <p>Applications usually need only call the inherited {@link #Search(Query)}
  24. /// or {@link #Search(Query,Filter)} methods.
  25. /// </summary>
  26. public class ParallelMultiSearcher : MultiSearcher
  27. {
  28. private class AnonymousClassHitCollector1 : HitCollector
  29. {
  30. public AnonymousClassHitCollector1(Lucene.Net.Search.HitCollector results, int start, ParallelMultiSearcher enclosingInstance)
  31. {
  32. InitBlock(results, start, enclosingInstance);
  33. }
  34. private void  InitBlock(Lucene.Net.Search.HitCollector results, int start, ParallelMultiSearcher enclosingInstance)
  35. {
  36. this.results = results;
  37. this.start = start;
  38. this.enclosingInstance = enclosingInstance;
  39. }
  40. private Lucene.Net.Search.HitCollector results;
  41. private int start;
  42. private ParallelMultiSearcher enclosingInstance;
  43. public ParallelMultiSearcher Enclosing_Instance
  44. {
  45. get
  46. {
  47. return enclosingInstance;
  48. }
  49. }
  50. public override void  Collect(int doc, float score)
  51. {
  52. results.Collect(doc + start, score);
  53. }
  54. }
  55. private Lucene.Net.Search.Searchable[] searchables;
  56. private int[] starts;
  57. /// <summary>Creates a searcher which searches <i>searchables</i>. </summary>
  58. public ParallelMultiSearcher(Lucene.Net.Search.Searchable[] searchables) : base(searchables)
  59. {
  60. this.searchables = searchables;
  61. this.starts = GetStarts();
  62. }
  63. /// <summary> TODO: parallelize this one too</summary>
  64. public override int DocFreq(Term term)
  65. {
  66. return base.DocFreq(term);
  67. }
  68. /// <summary> A search implementation which spans a new thread for each
  69. /// Searchable, waits for each search to complete and merge
  70. /// the results back together.
  71. /// </summary>
  72. public override TopDocs Search(Weight weight, Filter filter, int nDocs)
  73. {
  74. HitQueue hq = new HitQueue(nDocs);
  75. int totalHits = 0;
  76. MultiSearcherThread[] msta = new MultiSearcherThread[searchables.Length];
  77. for (int i = 0; i < searchables.Length; i++)
  78. {
  79. // search each searcher
  80. // Assume not too many searchables and cost of creating a thread is by far inferior to a search
  81. msta[i] = new MultiSearcherThread(searchables[i], weight, filter, nDocs, hq, i, starts, "MultiSearcher thread #" + (i + 1));
  82. msta[i].Start();
  83. }
  84. for (int i = 0; i < searchables.Length; i++)
  85. {
  86. try
  87. {
  88. msta[i].Join();
  89. }
  90. catch (System.Threading.ThreadInterruptedException)
  91. {
  92. ; // TODO: what should we do with this???
  93. }
  94. System.IO.IOException ioe = msta[i].GetIOException();
  95. if (ioe == null)
  96. {
  97. totalHits += msta[i].Hits();
  98. }
  99. else
  100. {
  101. // if one search produced an IOException, rethrow it
  102. throw ioe;
  103. }
  104. }
  105. ScoreDoc[] scoreDocs = new ScoreDoc[hq.Size()];
  106. for (int i = hq.Size() - 1; i >= 0; i--)
  107. // put docs in array
  108. scoreDocs[i] = (ScoreDoc) hq.Pop();
  109. float maxScore = (totalHits == 0) ? System.Single.NegativeInfinity : scoreDocs[0].score;
  110. return new TopDocs(totalHits, scoreDocs, maxScore);
  111. }
  112. /// <summary> A search implementation allowing sorting which spans a new thread for each
  113. /// Searchable, waits for each search to complete and merges
  114. /// the results back together.
  115. /// </summary>
  116. public override TopFieldDocs Search(Weight weight, Filter filter, int nDocs, Sort sort)
  117. {
  118. // don't specify the fields - we'll wait to do this until we get results
  119. FieldDocSortedHitQueue hq = new FieldDocSortedHitQueue(null, nDocs);
  120. int totalHits = 0;
  121. MultiSearcherThread[] msta = new MultiSearcherThread[searchables.Length];
  122. for (int i = 0; i < searchables.Length; i++)
  123. {
  124. // search each searcher
  125. // Assume not too many searchables and cost of creating a thread is by far inferior to a search
  126. msta[i] = new MultiSearcherThread(searchables[i], weight, filter, nDocs, hq, sort, i, starts, "MultiSearcher thread #" + (i + 1));
  127. msta[i].Start();
  128. }
  129. float maxScore = System.Single.NegativeInfinity;
  130. for (int i = 0; i < searchables.Length; i++)
  131. {
  132. try
  133. {
  134. msta[i].Join();
  135. }
  136. catch (System.Threading.ThreadInterruptedException)
  137. {
  138. ; // TODO: what should we do with this???
  139. }
  140. System.IO.IOException ioe = msta[i].GetIOException();
  141. if (ioe == null)
  142. {
  143. totalHits += msta[i].Hits();
  144. maxScore = System.Math.Max(maxScore, msta[i].GetMaxScore());
  145. }
  146. else
  147. {
  148. // if one search produced an IOException, rethrow it
  149. throw ioe;
  150. }
  151. }
  152. ScoreDoc[] scoreDocs = new ScoreDoc[hq.Size()];
  153. for (int i = hq.Size() - 1; i >= 0; i--)
  154. // put docs in array
  155. scoreDocs[i] = (ScoreDoc) hq.Pop();
  156. return new TopFieldDocs(totalHits, scoreDocs, hq.GetFields(), maxScore);
  157. }
  158. /// <summary>Lower-level search API.
  159. /// 
  160. /// <p>{@link HitCollector#Collect(int,float)} is called for every non-zero
  161. /// scoring document.
  162. /// 
  163. /// <p>Applications should only use this if they need <i>all</i> of the
  164. /// matching documents.  The high-level search API ({@link
  165. /// Searcher#Search(Query)}) is usually more efficient, as it skips
  166. /// non-high-scoring hits.
  167. /// 
  168. /// </summary>
  169. /// <param name="weight">to match documents
  170. /// </param>
  171. /// <param name="filter">if non-null, a bitset used to eliminate some documents
  172. /// </param>
  173. /// <param name="results">to receive hits
  174. /// 
  175. /// </param>
  176. /// <todo>  parallelize this one too </todo>
  177. public override void  Search(Weight weight, Filter filter, HitCollector results)
  178. {
  179. for (int i = 0; i < searchables.Length; i++)
  180. {
  181. int start = starts[i];
  182. searchables[i].Search(weight, filter, new AnonymousClassHitCollector1(results, start, this));
  183. }
  184. }
  185. /*
  186. * TODO: this one could be parallelized too
  187. * @see Lucene.Net.search.Searchable#rewrite(Lucene.Net.search.Query)
  188. */
  189. public override Query Rewrite(Query original)
  190. {
  191. return base.Rewrite(original);
  192. }
  193. }
  194. /// <summary> A thread subclass for searching a single searchable </summary>
  195. class MultiSearcherThread : SupportClass.ThreadClass
  196. {
  197. private Lucene.Net.Search.Searchable searchable;
  198. private Weight weight;
  199. private Filter filter;
  200. private int nDocs;
  201. private TopDocs docs;
  202. private int i;
  203. private PriorityQueue hq;
  204. private int[] starts;
  205. private System.IO.IOException ioe;
  206. private Sort sort;
  207. public MultiSearcherThread(Lucene.Net.Search.Searchable searchable, Weight weight, Filter filter, int nDocs, HitQueue hq, int i, int[] starts, System.String name):base(name)
  208. {
  209. this.searchable = searchable;
  210. this.weight = weight;
  211. this.filter = filter;
  212. this.nDocs = nDocs;
  213. this.hq = hq;
  214. this.i = i;
  215. this.starts = starts;
  216. }
  217. public MultiSearcherThread(Lucene.Net.Search.Searchable searchable, Weight weight, Filter filter, int nDocs, FieldDocSortedHitQueue hq, Sort sort, int i, int[] starts, System.String name):base(name)
  218. {
  219. this.searchable = searchable;
  220. this.weight = weight;
  221. this.filter = filter;
  222. this.nDocs = nDocs;
  223. this.hq = hq;
  224. this.i = i;
  225. this.starts = starts;
  226. this.sort = sort;
  227. }
  228. override public void  Run()
  229. {
  230. try
  231. {
  232. docs = (sort == null)?searchable.Search(weight, filter, nDocs):searchable.Search(weight, filter, nDocs, sort);
  233. }
  234. // Store the IOException for later use by the caller of this thread
  235. catch (System.IO.IOException ioe)
  236. {
  237. this.ioe = ioe;
  238. }
  239. if (this.ioe == null)
  240. {
  241. // if we are sorting by fields, we need to tell the field sorted hit queue
  242. // the actual type of fields, in case the original list contained AUTO.
  243. // if the searchable returns null for fields, we'll have problems.
  244. if (sort != null)
  245. {
  246. ((FieldDocSortedHitQueue) hq).SetFields(((TopFieldDocs) docs).fields);
  247. }
  248. ScoreDoc[] scoreDocs = docs.scoreDocs;
  249. for (int j = 0; j < scoreDocs.Length; j++)
  250. {
  251. // merge scoreDocs into hq
  252. ScoreDoc scoreDoc = scoreDocs[j];
  253. scoreDoc.doc += starts[i]; // convert doc 
  254. //it would be so nice if we had a thread-safe insert 
  255. lock (hq)
  256. {
  257. if (!hq.Insert(scoreDoc))
  258. break;
  259. } // no more scores > minScore
  260. }
  261. }
  262. }
  263. public virtual int Hits()
  264. {
  265. return docs.totalHits;
  266. }
  267. public virtual float GetMaxScore()
  268. {
  269. return docs.GetMaxScore();
  270. }
  271. public virtual System.IO.IOException GetIOException()
  272. {
  273. return ioe;
  274. }
  275. }
  276. }