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

搜索引擎

开发平台:

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
  20. {
  21. /// <summary> Expert: A hit queue for sorting by hits by terms in more than one field.
  22. /// Uses <code>FieldCache.DEFAULT</code> for maintaining internal term lookup tables.
  23. /// 
  24. /// <p>Created: Dec 8, 2003 12:56:03 PM
  25. /// 
  26. /// </summary>
  27. /// <author>   Tim Jones (Nacimiento Software)
  28. /// </author>
  29. /// <since>   lucene 1.4
  30. /// </since>
  31. /// <version>  $Id: FieldSortedHitQueue.java 354819 2005-12-07 17:48:37Z yonik $
  32. /// </version>
  33. /// <seealso cref="Searcher.Search(Query,Filter,int,Sort)">
  34. /// </seealso>
  35. /// <seealso cref="FieldCache">
  36. /// </seealso>
  37. class FieldSortedHitQueue : PriorityQueue
  38. {
  39. private class AnonymousClassScoreDocComparator : ScoreDocComparator
  40. {
  41. public AnonymousClassScoreDocComparator(int[] fieldOrder)
  42. {
  43. InitBlock(fieldOrder);
  44. }
  45. private void  InitBlock(int[] fieldOrder)
  46. {
  47. this.fieldOrder = fieldOrder;
  48. }
  49.             private int[] fieldOrder;
  50. public int Compare(ScoreDoc i, ScoreDoc j)
  51. {
  52. int fi = fieldOrder[i.doc];
  53. int fj = fieldOrder[j.doc];
  54. if (fi < fj)
  55. return - 1;
  56. if (fi > fj)
  57. return 1;
  58. return 0;
  59. }
  60. public virtual System.IComparable SortValue(ScoreDoc i)
  61. {
  62. return (System.Int32) fieldOrder[i.doc];
  63. }
  64. public virtual int SortType()
  65. {
  66. return SortField.INT;
  67. }
  68. }
  69. private class AnonymousClassScoreDocComparator1 : ScoreDocComparator
  70. {
  71. public AnonymousClassScoreDocComparator1(float[] fieldOrder)
  72. {
  73. InitBlock(fieldOrder);
  74. }
  75. private void  InitBlock(float[] fieldOrder)
  76. {
  77. this.fieldOrder = fieldOrder;
  78. }
  79. private float[] fieldOrder;
  80. public int Compare(ScoreDoc i, ScoreDoc j)
  81. {
  82. float fi = fieldOrder[i.doc];
  83. float fj = fieldOrder[j.doc];
  84. if (fi < fj)
  85. return - 1;
  86. if (fi > fj)
  87. return 1;
  88. return 0;
  89. }
  90. public virtual System.IComparable SortValue(ScoreDoc i)
  91. {
  92. return (float) fieldOrder[i.doc];
  93. }
  94. public virtual int SortType()
  95. {
  96. return SortField.FLOAT;
  97. }
  98. }
  99. private class AnonymousClassScoreDocComparator2 : ScoreDocComparator
  100. {
  101. public AnonymousClassScoreDocComparator2(Lucene.Net.Search.StringIndex index)
  102. {
  103. InitBlock(index);
  104. }
  105. private void  InitBlock(Lucene.Net.Search.StringIndex index)
  106. {
  107. this.index = index;
  108. }
  109. private Lucene.Net.Search.StringIndex index;
  110. public int Compare(ScoreDoc i, ScoreDoc j)
  111. {
  112. int fi = index.order[i.doc];
  113. int fj = index.order[j.doc];
  114. if (fi < fj)
  115. return - 1;
  116. if (fi > fj)
  117. return 1;
  118. return 0;
  119. }
  120. public virtual System.IComparable SortValue(ScoreDoc i)
  121. {
  122. return index.lookup[index.order[i.doc]];
  123. }
  124. public virtual int SortType()
  125. {
  126. return SortField.STRING;
  127. }
  128. }
  129. private class AnonymousClassScoreDocComparator3 : ScoreDocComparator
  130. {
  131. public AnonymousClassScoreDocComparator3(System.Globalization.CompareInfo collator, System.String[] index)
  132. {
  133. InitBlock(collator, index);
  134. }
  135. private void  InitBlock(System.Globalization.CompareInfo collator, System.String[] index)
  136. {
  137. this.collator = collator;
  138. this.index = index;
  139. }
  140. private System.Globalization.CompareInfo collator;
  141. private System.String[] index;
  142. public int Compare(ScoreDoc i, ScoreDoc j)
  143. {
  144. return collator.Compare(index[i.doc].ToString(), index[j.doc].ToString());
  145. }
  146. public virtual System.IComparable SortValue(ScoreDoc i)
  147. {
  148. return index[i.doc];
  149. }
  150. public virtual int SortType()
  151. {
  152. return SortField.STRING;
  153. }
  154. }
  155. /// <summary> Creates a hit queue sorted by the given list of fields.</summary>
  156. /// <param name="reader"> Index to use.
  157. /// </param>
  158. /// <param name="fields">Field names, in priority order (highest priority first).  Cannot be <code>null</code> or empty.
  159. /// </param>
  160. /// <param name="size"> The number of hits to retain.  Must be greater than zero.
  161. /// </param>
  162. /// <throws>  IOException </throws>
  163. internal FieldSortedHitQueue(IndexReader reader, SortField[] fields, int size)
  164. {
  165. int n = fields.Length;
  166. comparators = new ScoreDocComparator[n];
  167. this.fields = new SortField[n];
  168. for (int i = 0; i < n; ++i)
  169. {
  170. System.String fieldname = fields[i].GetField();
  171. comparators[i] = GetCachedComparator(reader, fieldname, fields[i].GetType(), fields[i].GetLocale(), fields[i].GetFactory());
  172. this.fields[i] = new SortField(fieldname, comparators[i].SortType(), fields[i].GetReverse());
  173. }
  174. Initialize(size);
  175. }
  176. /// <summary>Stores a comparator corresponding to each field being sorted by </summary>
  177. protected internal ScoreDocComparator[] comparators;
  178. /// <summary>Stores the sort criteria being used. </summary>
  179. protected internal SortField[] fields;
  180. /// <summary>Stores the maximum score value encountered, needed for normalizing. </summary>
  181. protected internal float maxscore = System.Single.NegativeInfinity;
  182. /// <summary>returns the maximum score encountered by elements inserted via insert()</summary>
  183. public virtual float GetMaxScore()
  184. {
  185. return maxscore;
  186. }
  187. // The signature of this method takes a FieldDoc in order to avoid
  188. // the unneeded cast to retrieve the score.
  189. // inherit javadoc
  190. public virtual bool Insert(FieldDoc fdoc)
  191. {
  192. maxscore = System.Math.Max(maxscore, fdoc.score);
  193. return base.Insert(fdoc);
  194. }
  195. // This overrides PriorityQueue.insert() so that insert(FieldDoc) that
  196. // keeps track of the score isn't accidentally bypassed.  
  197. // inherit javadoc
  198. public override bool Insert(System.Object fdoc)
  199. {
  200. return Insert((FieldDoc) fdoc);
  201. }
  202. /// <summary> Returns whether <code>a</code> is less relevant than <code>b</code>.</summary>
  203. /// <param name="a">ScoreDoc
  204. /// </param>
  205. /// <param name="b">ScoreDoc
  206. /// </param>
  207. /// <returns> <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>.
  208. /// </returns>
  209. public override bool LessThan(System.Object a, System.Object b)
  210. {
  211. ScoreDoc docA = (ScoreDoc) a;
  212. ScoreDoc docB = (ScoreDoc) b;
  213. // run comparators
  214. int n = comparators.Length;
  215. int c = 0;
  216. for (int i = 0; i < n && c == 0; ++i)
  217. {
  218. c = (fields[i].reverse)?comparators[i].Compare(docB, docA):comparators[i].Compare(docA, docB);
  219. }
  220. // avoid random sort order that could lead to duplicates (bug #31241):
  221. if (c == 0)
  222. return docA.doc > docB.doc;
  223. return c > 0;
  224. }
  225. /// <summary> Given a FieldDoc object, stores the values used
  226. /// to sort the given document.  These values are not the raw
  227. /// values out of the index, but the internal representation
  228. /// of them.  This is so the given search hit can be collated
  229. /// by a MultiSearcher with other search hits.
  230. /// </summary>
  231. /// <param name="doc"> The FieldDoc to store sort values into.
  232. /// </param>
  233. /// <returns>  The same FieldDoc passed in.
  234. /// </returns>
  235. /// <seealso cref="Searchable.Search(Weight,Filter,int,Sort)">
  236. /// </seealso>
  237. internal virtual FieldDoc FillFields(FieldDoc doc)
  238. {
  239. int n = comparators.Length;
  240. System.IComparable[] fields = new System.IComparable[n];
  241. for (int i = 0; i < n; ++i)
  242. fields[i] = comparators[i].SortValue(doc);
  243. doc.fields = fields;
  244. //if (maxscore > 1.0f) doc.score /= maxscore;   // normalize scores
  245. return doc;
  246. }
  247. /// <summary>Returns the SortFields being used by this hit queue. </summary>
  248. internal virtual SortField[] GetFields()
  249. {
  250. return fields;
  251. }
  252. /// <summary>Internal cache of comparators. Similar to FieldCache, only
  253. /// caches comparators instead of term values. 
  254. /// </summary>
  255. internal static readonly System.Collections.IDictionary Comparators = new System.Collections.Hashtable();
  256. /// <summary>Returns a comparator if it is in the cache. </summary>
  257. internal static ScoreDocComparator Lookup(IndexReader reader, System.String field, int type, System.Object factory)
  258. {
  259. FieldCacheImpl.Entry entry = (factory != null) ? new FieldCacheImpl.Entry(field, factory) : new FieldCacheImpl.Entry(field, type);
  260. lock (Comparators.SyncRoot)
  261. {
  262. System.Collections.Hashtable readerCache = (System.Collections.Hashtable) Comparators[reader];
  263. if (readerCache == null)
  264. return null;
  265. return (ScoreDocComparator) readerCache[entry];
  266. }
  267. }
  268. /// <summary>Stores a comparator into the cache. </summary>
  269. internal static System.Object Store(IndexReader reader, System.String field, int type, System.Object factory, System.Object value_Renamed)
  270. {
  271. FieldCacheImpl.Entry entry = (factory != null) ? new FieldCacheImpl.Entry(field, factory) : new FieldCacheImpl.Entry(field, type);
  272. lock (Comparators.SyncRoot)
  273. {
  274. System.Collections.Hashtable readerCache = (System.Collections.Hashtable) Comparators[reader];
  275. if (readerCache == null)
  276. {
  277. readerCache = new System.Collections.Hashtable();
  278. Comparators[reader] = readerCache;
  279. }
  280. System.Object tempObject;
  281. tempObject = readerCache[entry];
  282. readerCache[entry] = value_Renamed;
  283. return tempObject;
  284. }
  285. }
  286. internal static ScoreDocComparator GetCachedComparator(IndexReader reader, System.String fieldname, int type, System.Globalization.CultureInfo locale, SortComparatorSource factory)
  287. {
  288. if (type == SortField.DOC)
  289. return Lucene.Net.Search.ScoreDocComparator_Fields.INDEXORDER;
  290. if (type == SortField.SCORE)
  291. return Lucene.Net.Search.ScoreDocComparator_Fields.RELEVANCE;
  292. ScoreDocComparator comparator = Lookup(reader, fieldname, type, factory);
  293. if (comparator == null)
  294. {
  295. switch (type)
  296. {
  297. case SortField.AUTO: 
  298. comparator = ComparatorAuto(reader, fieldname);
  299. break;
  300. case SortField.INT: 
  301. comparator = ComparatorInt(reader, fieldname);
  302. break;
  303. case SortField.FLOAT: 
  304. comparator = ComparatorFloat(reader, fieldname);
  305. break;
  306. case SortField.STRING: 
  307. if (locale != null)
  308. comparator = ComparatorStringLocale(reader, fieldname, locale);
  309. else
  310. comparator = ComparatorString(reader, fieldname);
  311. break;
  312. case SortField.CUSTOM: 
  313. comparator = factory.NewComparator(reader, fieldname);
  314. break;
  315. default: 
  316. throw new System.SystemException("unknown field type: " + type);
  317. }
  318. Store(reader, fieldname, type, factory, comparator);
  319. }
  320. return comparator;
  321. }
  322. /// <summary> Returns a comparator for sorting hits according to a field containing integers.</summary>
  323. /// <param name="reader"> Index to use.
  324. /// </param>
  325. /// <param name="fieldname"> Field containg integer values.
  326. /// </param>
  327. /// <returns>  Comparator for sorting hits.
  328. /// </returns>
  329. /// <throws>  IOException If an error occurs reading the index. </throws>
  330. internal static ScoreDocComparator ComparatorInt(IndexReader reader, System.String fieldname)
  331. {
  332. System.String field = String.Intern(fieldname);
  333. int[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetInts(reader, field);
  334. return new AnonymousClassScoreDocComparator(fieldOrder);
  335. }
  336. /// <summary> Returns a comparator for sorting hits according to a field containing floats.</summary>
  337. /// <param name="reader"> Index to use.
  338. /// </param>
  339. /// <param name="fieldname"> Field containg float values.
  340. /// </param>
  341. /// <returns>  Comparator for sorting hits.
  342. /// </returns>
  343. /// <throws>  IOException If an error occurs reading the index. </throws>
  344. internal static ScoreDocComparator ComparatorFloat(IndexReader reader, System.String fieldname)
  345. {
  346. System.String field = String.Intern(fieldname);
  347. float[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetFloats(reader, field);
  348. return new AnonymousClassScoreDocComparator1(fieldOrder);
  349. }
  350. /// <summary> Returns a comparator for sorting hits according to a field containing strings.</summary>
  351. /// <param name="reader"> Index to use.
  352. /// </param>
  353. /// <param name="fieldname"> Field containg string values.
  354. /// </param>
  355. /// <returns>  Comparator for sorting hits.
  356. /// </returns>
  357. /// <throws>  IOException If an error occurs reading the index. </throws>
  358. internal static ScoreDocComparator ComparatorString(IndexReader reader, System.String fieldname)
  359. {
  360. System.String field = String.Intern(fieldname);
  361. Lucene.Net.Search.StringIndex index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStringIndex(reader, field);
  362. return new AnonymousClassScoreDocComparator2(index);
  363. }
  364. /// <summary> Returns a comparator for sorting hits according to a field containing strings.</summary>
  365. /// <param name="reader"> Index to use.
  366. /// </param>
  367. /// <param name="fieldname"> Field containg string values.
  368. /// </param>
  369. /// <returns>  Comparator for sorting hits.
  370. /// </returns>
  371. /// <throws>  IOException If an error occurs reading the index. </throws>
  372. internal static ScoreDocComparator ComparatorStringLocale(IndexReader reader, System.String fieldname, System.Globalization.CultureInfo locale)
  373. {
  374. System.Globalization.CompareInfo collator = locale.CompareInfo;
  375. System.String field = String.Intern(fieldname);
  376. System.String[] index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStrings(reader, field);
  377. return new AnonymousClassScoreDocComparator3(collator, index);
  378. }
  379. /// <summary> Returns a comparator for sorting hits according to values in the given field.
  380. /// The terms in the field are looked at to determine whether they contain integers,
  381. /// floats or strings.  Once the type is determined, one of the other static methods
  382. /// in this class is called to get the comparator.
  383. /// </summary>
  384. /// <param name="reader"> Index to use.
  385. /// </param>
  386. /// <param name="fieldname"> Field containg values.
  387. /// </param>
  388. /// <returns>  Comparator for sorting hits.
  389. /// </returns>
  390. /// <throws>  IOException If an error occurs reading the index. </throws>
  391. internal static ScoreDocComparator ComparatorAuto(IndexReader reader, System.String fieldname)
  392. {
  393. System.String field = String.Intern(fieldname);
  394. System.Object lookupArray = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetAuto(reader, field);
  395. if (lookupArray is Lucene.Net.Search.StringIndex)
  396. {
  397. return ComparatorString(reader, field);
  398. }
  399. else if (lookupArray is int[])
  400. {
  401. return ComparatorInt(reader, field);
  402. }
  403. else if (lookupArray is float[])
  404. {
  405. return ComparatorFloat(reader, field);
  406. }
  407. else if (lookupArray is System.String[])
  408. {
  409. return ComparatorString(reader, field);
  410. }
  411. else
  412. {
  413. throw new System.SystemException("unknown data type in field '" + field + "'");
  414. }
  415. }
  416. }
  417. }