Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / beagled / Lucene.Net / Search / FieldSortedHitQueue.cs
blob5465448f2a2b4b75dc424ff3ed5905f1565f476a
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.
16 using System;
17 using IndexReader = Lucene.Net.Index.IndexReader;
18 using PriorityQueue = Lucene.Net.Util.PriorityQueue;
19 namespace Lucene.Net.Search
22 /// <summary> Expert: A hit queue for sorting by hits by terms in more than one Field.
23 /// Uses <code>FieldCache.DEFAULT</code> for maintaining internal term lookup tables.
24 ///
25 /// <p>Created: Dec 8, 2003 12:56:03 PM
26 ///
27 /// </summary>
28 /// <author> Tim Jones (Nacimiento Software)
29 /// </author>
30 /// <since> lucene 1.4
31 /// </since>
32 /// <version> $Id: FieldSortedHitQueue.cs,v 1.1 2005/01/17 19:54:30 joeshaw Exp $
33 /// </version>
34 /// <seealso cref="Searchable#Search(Query,Filter,int,Sort)">
35 /// </seealso>
36 /// <seealso cref="FieldCache">
37 /// </seealso>
38 class FieldSortedHitQueue : PriorityQueue
40 private class AnonymousClassScoreDocComparator : ScoreDocComparator
42 public AnonymousClassScoreDocComparator(int[] fieldOrder)
44 InitBlock(fieldOrder);
46 private void InitBlock(int[] fieldOrder)
48 this.fieldOrder = fieldOrder;
51 private int[] fieldOrder;
53 public int Compare(ScoreDoc i, ScoreDoc j)
55 int fi = fieldOrder[i.doc];
56 int fj = fieldOrder[j.doc];
57 if (fi < fj)
58 return - 1;
59 if (fi > fj)
60 return 1;
61 return 0;
64 public virtual System.IComparable SortValue(ScoreDoc i)
66 return (System.Int32) fieldOrder[i.doc];
69 public virtual int SortType()
71 return SortField.INT;
74 private class AnonymousClassScoreDocComparator1 : ScoreDocComparator
76 public AnonymousClassScoreDocComparator1(float[] fieldOrder)
78 InitBlock(fieldOrder);
80 private void InitBlock(float[] fieldOrder)
82 this.fieldOrder = fieldOrder;
84 private float[] fieldOrder;
86 public int Compare(ScoreDoc i, ScoreDoc j)
88 float fi = fieldOrder[i.doc];
89 float fj = fieldOrder[j.doc];
90 if (fi < fj)
91 return - 1;
92 if (fi > fj)
93 return 1;
94 return 0;
97 public virtual System.IComparable SortValue(ScoreDoc i)
99 return (float) fieldOrder[i.doc];
102 public virtual int SortType()
104 return SortField.FLOAT;
107 private class AnonymousClassScoreDocComparator2 : ScoreDocComparator
109 public AnonymousClassScoreDocComparator2(Lucene.Net.Search.StringIndex index)
111 InitBlock(index);
113 private void InitBlock(Lucene.Net.Search.StringIndex index)
115 this.index = index;
117 private Lucene.Net.Search.StringIndex index;
119 public int Compare(ScoreDoc i, ScoreDoc j)
121 int fi = index.order[i.doc];
122 int fj = index.order[j.doc];
123 if (fi < fj)
124 return - 1;
125 if (fi > fj)
126 return 1;
127 return 0;
130 public virtual System.IComparable SortValue(ScoreDoc i)
132 return index.lookup[index.order[i.doc]];
135 public virtual int SortType()
137 return SortField.STRING;
140 private class AnonymousClassScoreDocComparator3 : ScoreDocComparator
142 public AnonymousClassScoreDocComparator3(System.Globalization.CompareInfo collator, System.String[] index)
144 InitBlock(collator, index);
146 private void InitBlock(System.Globalization.CompareInfo collator, System.String[] index)
148 this.collator = collator;
149 this.index = index;
151 private System.Globalization.CompareInfo collator;
152 private System.String[] index;
154 public int Compare(ScoreDoc i, ScoreDoc j)
156 return collator.Compare(index[i.doc].ToString(), index[j.doc].ToString());
159 public virtual System.IComparable SortValue(ScoreDoc i)
161 return index[i.doc];
164 public virtual int SortType()
166 return SortField.STRING;
170 /// <summary> Creates a hit queue sorted by the given list of fields.</summary>
171 /// <param name="reader"> Index to use.
172 /// </param>
173 /// <param name="fields">Field names, in priority order (highest priority first). Cannot be <code>null</code> or empty.
174 /// </param>
175 /// <param name="size"> The number of hits to retain. Must be greater than zero.
176 /// </param>
177 /// <throws> IOException </throws>
178 internal FieldSortedHitQueue(IndexReader reader, SortField[] fields, int size)
180 int n = fields.Length;
181 comparators = new ScoreDocComparator[n];
182 this.fields = new SortField[n];
183 for (int i = 0; i < n; ++i)
185 System.String fieldname = fields[i].GetField();
186 comparators[i] = GetCachedComparator(reader, fieldname, fields[i].GetType(), fields[i].GetLocale(), fields[i].GetFactory());
187 this.fields[i] = new SortField(fieldname, comparators[i].SortType(), fields[i].GetReverse());
189 Initialize(size);
193 /// <summary>Stores a comparator corresponding to each Field being sorted by </summary>
194 protected internal ScoreDocComparator[] comparators;
196 /// <summary>Stores the sort criteria being used. </summary>
197 protected internal SortField[] fields;
199 /// <summary>Stores the maximum score value encountered, for normalizing.
200 /// we only care about scores greater than 1.0 - if all the scores
201 /// are less than 1.0, we don't have to normalize.
202 /// </summary>
203 protected internal float maxscore = 1.0f;
206 /// <summary> Returns whether <code>a</code> is less relevant than <code>b</code>.</summary>
207 /// <param name="a">ScoreDoc
208 /// </param>
209 /// <param name="b">ScoreDoc
210 /// </param>
211 /// <returns> <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>.
212 /// </returns>
213 public override bool LessThan(System.Object a, System.Object b)
215 ScoreDoc docA = (ScoreDoc) a;
216 ScoreDoc docB = (ScoreDoc) b;
218 // keep track of maximum score
219 if (docA.score > maxscore)
220 maxscore = docA.score;
221 if (docB.score > maxscore)
222 maxscore = docB.score;
224 // run comparators
225 int n = comparators.Length;
226 int c = 0;
227 for (int i = 0; i < n && c == 0; ++i)
229 c = (fields[i].reverse) ? comparators[i].Compare(docB, docA) : comparators[i].Compare(docA, docB);
231 // avoid random sort order that could lead to duplicates (bug #31241):
232 if (c == 0)
233 return docA.doc > docB.doc;
234 return c > 0;
238 /// <summary> Given a FieldDoc object, stores the values used
239 /// to sort the given document. These values are not the raw
240 /// values out of the index, but the internal representation
241 /// of them. This is so the given search hit can be collated
242 /// by a MultiSearcher with other search hits.
243 /// </summary>
244 /// <param name="doc"> The FieldDoc to store sort values into.
245 /// </param>
246 /// <returns> The same FieldDoc passed in.
247 /// </returns>
248 /// <seealso cref="Searchable#Search(Query,Filter,int,Sort)">
249 /// </seealso>
250 internal virtual FieldDoc FillFields(FieldDoc doc)
252 int n = comparators.Length;
253 System.IComparable[] fields = new System.IComparable[n];
254 for (int i = 0; i < n; ++i)
255 fields[i] = comparators[i].SortValue(doc);
256 doc.fields = fields;
257 if (maxscore > 1.0f)
258 doc.score /= maxscore; // normalize scores
259 return doc;
263 /// <summary>Returns the SortFields being used by this hit queue. </summary>
264 internal virtual SortField[] GetFields()
266 return fields;
269 /// <summary>Internal cache of comparators. Similar to FieldCache, only
270 /// caches comparators instead of term values.
271 /// </summary>
272 internal static readonly System.Collections.IDictionary Comparators = new System.Collections.Hashtable();
274 /// <summary>Returns a comparator if it is in the cache. </summary>
275 internal static ScoreDocComparator Lookup(IndexReader reader, System.String field, int type, System.Object factory)
277 FieldCacheImpl.Entry entry = (factory != null) ? new FieldCacheImpl.Entry(field, factory) : new FieldCacheImpl.Entry(field, type);
278 lock (Comparators.SyncRoot)
280 System.Collections.Hashtable readerCache = (System.Collections.Hashtable) Comparators[reader];
281 if (readerCache == null)
282 return null;
283 return (ScoreDocComparator) readerCache[entry];
287 /// <summary>Stores a comparator into the cache. </summary>
288 internal static System.Object Store(IndexReader reader, System.String field, int type, System.Object factory, System.Object value_Renamed)
290 FieldCacheImpl.Entry entry = (factory != null) ? new FieldCacheImpl.Entry(field, factory) : new FieldCacheImpl.Entry(field, type);
291 lock (Comparators.SyncRoot)
293 System.Collections.Hashtable readerCache = (System.Collections.Hashtable) Comparators[reader];
294 if (readerCache == null)
296 readerCache = new System.Collections.Hashtable();
297 Comparators[reader] = readerCache;
299 System.Object tempObject;
300 tempObject = readerCache[entry];
301 readerCache[entry] = value_Renamed;
302 return tempObject;
306 internal static ScoreDocComparator GetCachedComparator(IndexReader reader, System.String fieldname, int type, System.Globalization.CultureInfo locale, SortComparatorSource factory)
308 if (type == SortField.DOC)
309 return Lucene.Net.Search.ScoreDocComparator_Fields.INDEXORDER;
310 if (type == SortField.SCORE)
311 return Lucene.Net.Search.ScoreDocComparator_Fields.RELEVANCE;
312 ScoreDocComparator comparator = Lookup(reader, fieldname, type, factory);
313 if (comparator == null)
315 switch (type)
318 case SortField.AUTO:
319 comparator = ComparatorAuto(reader, fieldname);
320 break;
322 case SortField.INT:
323 comparator = ComparatorInt(reader, fieldname);
324 break;
326 case SortField.FLOAT:
327 comparator = ComparatorFloat(reader, fieldname);
328 break;
330 case SortField.STRING:
331 if (locale != null)
332 comparator = ComparatorStringLocale(reader, fieldname, locale);
333 else
334 comparator = ComparatorString(reader, fieldname);
335 break;
337 case SortField.CUSTOM:
338 comparator = factory.NewComparator(reader, fieldname);
339 break;
341 default:
342 throw new System.SystemException("unknown Field type: " + type);
345 Store(reader, fieldname, type, factory, comparator);
347 return comparator;
350 /// <summary> Returns a comparator for sorting hits according to a Field containing integers.</summary>
351 /// <param name="reader"> Index to use.
352 /// </param>
353 /// <param name="fieldname"> Field containg integer 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 ComparatorInt(IndexReader reader, System.String fieldname)
360 System.String field = String.Intern(fieldname);
361 int[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetInts(reader, field);
362 return new AnonymousClassScoreDocComparator(fieldOrder);
365 /// <summary> Returns a comparator for sorting hits according to a Field containing floats.</summary>
366 /// <param name="reader"> Index to use.
367 /// </param>
368 /// <param name="fieldname"> Field containg float values.
369 /// </param>
370 /// <returns> Comparator for sorting hits.
371 /// </returns>
372 /// <throws> IOException If an error occurs reading the index. </throws>
373 internal static ScoreDocComparator ComparatorFloat(IndexReader reader, System.String fieldname)
375 System.String field = String.Intern(fieldname);
376 float[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetFloats(reader, field);
377 return new AnonymousClassScoreDocComparator1(fieldOrder);
380 /// <summary> Returns a comparator for sorting hits according to a Field containing strings.</summary>
381 /// <param name="reader"> Index to use.
382 /// </param>
383 /// <param name="fieldname"> Field containg string values.
384 /// </param>
385 /// <returns> Comparator for sorting hits.
386 /// </returns>
387 /// <throws> IOException If an error occurs reading the index. </throws>
388 internal static ScoreDocComparator ComparatorString(IndexReader reader, System.String fieldname)
390 System.String field = String.Intern(fieldname);
391 Lucene.Net.Search.StringIndex index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStringIndex(reader, field);
392 return new AnonymousClassScoreDocComparator2(index);
395 /// <summary> Returns a comparator for sorting hits according to a Field containing strings.</summary>
396 /// <param name="reader"> Index to use.
397 /// </param>
398 /// <param name="fieldname"> Field containg string values.
399 /// </param>
400 /// <returns> Comparator for sorting hits.
401 /// </returns>
402 /// <throws> IOException If an error occurs reading the index. </throws>
403 internal static ScoreDocComparator ComparatorStringLocale(IndexReader reader, System.String fieldname, System.Globalization.CultureInfo locale)
405 System.Globalization.CompareInfo collator = locale.CompareInfo;
406 System.String field = String.Intern(fieldname);
407 System.String[] index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStrings(reader, field);
408 return new AnonymousClassScoreDocComparator3(collator, index);
411 /// <summary> Returns a comparator for sorting hits according to values in the given Field.
412 /// The terms in the Field are looked at to determine whether they contain integers,
413 /// floats or strings. Once the type is determined, one of the other static methods
414 /// in this class is called to get the comparator.
415 /// </summary>
416 /// <param name="reader"> Index to use.
417 /// </param>
418 /// <param name="fieldname"> Field containg values.
419 /// </param>
420 /// <returns> Comparator for sorting hits.
421 /// </returns>
422 /// <throws> IOException If an error occurs reading the index. </throws>
423 internal static ScoreDocComparator ComparatorAuto(IndexReader reader, System.String fieldname)
425 System.String field = String.Intern(fieldname);
426 System.Object lookupArray = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetAuto(reader, field);
427 if (lookupArray is Lucene.Net.Search.StringIndex)
429 return ComparatorString(reader, field);
431 else if (lookupArray is int[])
433 return ComparatorInt(reader, field);
435 else if (lookupArray is float[])
437 return ComparatorFloat(reader, field);
439 else if (lookupArray is System.String[])
441 return ComparatorString(reader, field);
443 else
445 throw new System.SystemException("unknown data type in Field '" + field + "'");