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

搜索引擎

开发平台:

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 Document = Lucene.Net.Documents.Document;
  18. using Term = Lucene.Net.Index.Term;
  19. namespace Lucene.Net.Search
  20. {
  21. /// <summary>Implements 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 MultiSearcher : Searcher
  27. {
  28. private class AnonymousClassHitCollector : HitCollector
  29. {
  30. public AnonymousClassHitCollector(Lucene.Net.Search.HitCollector results, int start, MultiSearcher enclosingInstance)
  31. {
  32. InitBlock(results, start, enclosingInstance);
  33. }
  34. private void  InitBlock(Lucene.Net.Search.HitCollector results, int start, MultiSearcher 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 MultiSearcher enclosingInstance;
  43. public MultiSearcher 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. /// <summary> Document Frequency cache acting as a Dummy-Searcher.
  56. /// This class is no full-fledged Searcher, but only supports
  57. /// the methods necessary to initialize Weights.
  58. /// </summary>
  59. private class CachedDfSource:Searcher
  60. {
  61. private System.Collections.IDictionary dfMap; // Map from Terms to corresponding doc freqs
  62. private int maxDoc; // document count
  63. public CachedDfSource(System.Collections.IDictionary dfMap, int maxDoc)
  64. {
  65. this.dfMap = dfMap;
  66. this.maxDoc = maxDoc;
  67. }
  68. public override int DocFreq(Term term)
  69. {
  70. int df;
  71. try
  72. {
  73. df = ((System.Int32) dfMap[term]);
  74. }
  75. catch (System.NullReferenceException)
  76. {
  77. throw new System.ArgumentException("df for term " + term.Text() + " not available");
  78. }
  79. return df;
  80. }
  81. public override int[] DocFreqs(Term[] terms)
  82. {
  83. int[] result = new int[terms.Length];
  84. for (int i = 0; i < terms.Length; i++)
  85. {
  86. result[i] = DocFreq(terms[i]);
  87. }
  88. return result;
  89. }
  90. public override int MaxDoc()
  91. {
  92. return maxDoc;
  93. }
  94. public override Query Rewrite(Query query)
  95. {
  96. // this is a bit of a hack. We know that a query which
  97. // creates a Weight based on this Dummy-Searcher is
  98. // always already rewritten (see preparedWeight()).
  99. // Therefore we just return the unmodified query here
  100. return query;
  101. }
  102. public override void  Close()
  103. {
  104. throw new System.NotSupportedException();
  105. }
  106. public override Document Doc(int i)
  107. {
  108. throw new System.NotSupportedException();
  109. }
  110. public override Explanation Explain(Weight weight, int doc)
  111. {
  112. throw new System.NotSupportedException();
  113. }
  114. public override void  Search(Weight weight, Filter filter, HitCollector results)
  115. {
  116. throw new System.NotSupportedException();
  117. }
  118. public override TopDocs Search(Weight weight, Filter filter, int n)
  119. {
  120. throw new System.NotSupportedException();
  121. }
  122. public override TopFieldDocs Search(Weight weight, Filter filter, int n, Sort sort)
  123. {
  124. throw new System.NotSupportedException();
  125. }
  126. }
  127. private Lucene.Net.Search.Searchable[] searchables;
  128. private int[] starts;
  129. private int maxDoc = 0;
  130. /// <summary>Creates a searcher which searches <i>searchables</i>. </summary>
  131. public MultiSearcher(Lucene.Net.Search.Searchable[] searchables)
  132. {
  133. this.searchables = searchables;
  134. starts = new int[searchables.Length + 1]; // build starts array
  135. for (int i = 0; i < searchables.Length; i++)
  136. {
  137. starts[i] = maxDoc;
  138. maxDoc += searchables[i].MaxDoc(); // compute maxDocs
  139. }
  140. starts[searchables.Length] = maxDoc;
  141. }
  142. /// <summary>Return the array of {@link Searchable}s this searches. </summary>
  143. public virtual Lucene.Net.Search.Searchable[] GetSearchables()
  144. {
  145. return searchables;
  146. }
  147. protected internal virtual int[] GetStarts()
  148. {
  149. return starts;
  150. }
  151. // inherit javadoc
  152. public override void  Close()
  153. {
  154. for (int i = 0; i < searchables.Length; i++)
  155. searchables[i].Close();
  156. }
  157. public override int DocFreq(Term term)
  158. {
  159. int docFreq = 0;
  160. for (int i = 0; i < searchables.Length; i++)
  161. docFreq += searchables[i].DocFreq(term);
  162. return docFreq;
  163. }
  164. // inherit javadoc
  165. public override Document Doc(int n)
  166. {
  167. int i = SubSearcher(n); // find searcher index
  168. return searchables[i].Doc(n - starts[i]); // dispatch to searcher
  169. }
  170. /// <summary>Call {@link #subSearcher} instead.</summary>
  171. /// <deprecated>
  172. /// </deprecated>
  173. public virtual int SearcherIndex(int n)
  174. {
  175. return SubSearcher(n);
  176. }
  177. /// <summary>Returns index of the searcher for document <code>n</code> in the array
  178. /// used to construct this searcher. 
  179. /// </summary>
  180. public virtual int SubSearcher(int n)
  181. {
  182. // find searcher for doc n:
  183. // replace w/ call to Arrays.binarySearch in Java 1.2
  184. int lo = 0; // search starts array
  185. int hi = searchables.Length - 1; // for first element less
  186. // than n, return its index
  187. while (hi >= lo)
  188. {
  189. int mid = (lo + hi) >> 1;
  190. int midValue = starts[mid];
  191. if (n < midValue)
  192. hi = mid - 1;
  193. else if (n > midValue)
  194. lo = mid + 1;
  195. else
  196. {
  197. // found a match
  198. while (mid + 1 < searchables.Length && starts[mid + 1] == midValue)
  199. {
  200. mid++; // scan to last match
  201. }
  202. return mid;
  203. }
  204. }
  205. return hi;
  206. }
  207. /// <summary>Returns the document number of document <code>n</code> within its
  208. /// sub-index. 
  209. /// </summary>
  210. public virtual int SubDoc(int n)
  211. {
  212. return n - starts[SubSearcher(n)];
  213. }
  214. public override int MaxDoc()
  215. {
  216. return maxDoc;
  217. }
  218. public override TopDocs Search(Weight weight, Filter filter, int nDocs)
  219. {
  220. HitQueue hq = new HitQueue(nDocs);
  221. int totalHits = 0;
  222. for (int i = 0; i < searchables.Length; i++)
  223. {
  224. // search each searcher
  225. TopDocs docs = searchables[i].Search(weight, filter, nDocs);
  226. totalHits += docs.totalHits; // update totalHits
  227. ScoreDoc[] scoreDocs = docs.scoreDocs;
  228. for (int j = 0; j < scoreDocs.Length; j++)
  229. {
  230. // merge scoreDocs into hq
  231. ScoreDoc scoreDoc = scoreDocs[j];
  232. scoreDoc.doc += starts[i]; // convert doc
  233. if (!hq.Insert(scoreDoc))
  234. break; // no more scores > minScore
  235. }
  236. }
  237. ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()];
  238. for (int i = hq.Size() - 1; i >= 0; i--)
  239.     // put docs in array
  240. scoreDocs2[i] = (ScoreDoc) hq.Pop();
  241. float maxScore = (totalHits == 0) ? System.Single.NegativeInfinity : scoreDocs2[0].score;
  242. return new TopDocs(totalHits, scoreDocs2, maxScore);
  243. }
  244. public override TopFieldDocs Search(Weight weight, Filter filter, int n, Sort sort)
  245. {
  246. FieldDocSortedHitQueue hq = null;
  247. int totalHits = 0;
  248. float maxScore = System.Single.NegativeInfinity;
  249. for (int i = 0; i < searchables.Length; i++)
  250. {
  251. // search each searcher
  252. TopFieldDocs docs = searchables[i].Search(weight, filter, n, sort);
  253. if (hq == null)
  254. hq = new FieldDocSortedHitQueue(docs.fields, n);
  255. totalHits += docs.totalHits; // update totalHits
  256. maxScore = System.Math.Max(maxScore, docs.GetMaxScore());
  257. ScoreDoc[] scoreDocs = docs.scoreDocs;
  258. for (int j = 0; j < scoreDocs.Length; j++)
  259. {
  260. // merge scoreDocs into hq
  261. ScoreDoc scoreDoc = scoreDocs[j];
  262. scoreDoc.doc += starts[i]; // convert doc
  263. if (!hq.Insert(scoreDoc))
  264. break; // no more scores > minScore
  265. }
  266. }
  267. ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()];
  268. for (int i = hq.Size() - 1; i >= 0; i--)
  269.     // put docs in array
  270. scoreDocs2[i] = (ScoreDoc) hq.Pop();
  271. return new TopFieldDocs(totalHits, scoreDocs2, hq.GetFields(), maxScore);
  272. }
  273. // inherit javadoc
  274. public override void  Search(Weight weight, Filter filter, HitCollector results)
  275. {
  276. for (int i = 0; i < searchables.Length; i++)
  277. {
  278. int start = starts[i];
  279. searchables[i].Search(weight, filter, new AnonymousClassHitCollector(results, start, this));
  280. }
  281. }
  282. public override Query Rewrite(Query original)
  283. {
  284. Query[] queries = new Query[searchables.Length];
  285. for (int i = 0; i < searchables.Length; i++)
  286. {
  287. queries[i] = searchables[i].Rewrite(original);
  288. }
  289. return queries[0].Combine(queries);
  290. }
  291. public override Explanation Explain(Weight weight, int doc)
  292. {
  293. int i = SubSearcher(doc); // find searcher index
  294. return searchables[i].Explain(weight, doc - starts[i]); // dispatch to searcher
  295. }
  296. /// <summary> Create weight in multiple index scenario.
  297. /// 
  298. /// Distributed query processing is done in the following steps:
  299. /// 1. rewrite query
  300. /// 2. extract necessary terms
  301. /// 3. collect dfs for these terms from the Searchables
  302. /// 4. create query weight using aggregate dfs.
  303. /// 5. distribute that weight to Searchables
  304. /// 6. merge results
  305. /// 
  306. /// Steps 1-4 are done here, 5+6 in the search() methods
  307. /// 
  308. /// </summary>
  309. /// <returns> rewritten queries
  310. /// </returns>
  311. protected internal override Weight CreateWeight(Query original)
  312. {
  313. // step 1
  314. Query rewrittenQuery = Rewrite(original);
  315. // step 2
  316. System.Collections.Hashtable terms = new System.Collections.Hashtable();
  317. rewrittenQuery.ExtractTerms(terms);
  318. // step3
  319. Term[] allTermsArray = new Term[terms.Count];
  320.             int index = 0;
  321.             System.Collections.IEnumerator e = terms.GetEnumerator();
  322.             while (e.MoveNext())
  323.                 allTermsArray[index++] = e.Current as Term;
  324. int[] aggregatedDfs = new int[terms.Count];
  325. for (int i = 0; i < searchables.Length; i++)
  326. {
  327. int[] dfs = searchables[i].DocFreqs(allTermsArray);
  328. for (int j = 0; j < aggregatedDfs.Length; j++)
  329. {
  330. aggregatedDfs[j] += dfs[j];
  331. }
  332. }
  333. System.Collections.Hashtable dfMap = new System.Collections.Hashtable();
  334. for (int i = 0; i < allTermsArray.Length; i++)
  335. {
  336. dfMap[allTermsArray[i]] = (System.Int32) aggregatedDfs[i];
  337. }
  338. // step4
  339. int numDocs = MaxDoc();
  340. CachedDfSource cacheSim = new CachedDfSource(dfMap, numDocs);
  341. return rewrittenQuery.Weight(cacheSim);
  342. }
  343. }
  344. }