Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
SortField.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Globalization;
20 using Lucene.Net.Support;
21 using NumericField = Lucene.Net.Documents.NumericField;
22 using IndexReader = Lucene.Net.Index.IndexReader;
23 using Single = Lucene.Net.Support.Single;
24 using Term = Lucene.Net.Index.Term;
25 using TermEnum = Lucene.Net.Index.TermEnum;
26 using StringHelper = Lucene.Net.Util.StringHelper;
27 
28 namespace Lucene.Net.Search
29 {
30 
31  /// <summary> Stores information about how to sort documents by terms in an individual
32  /// field. Fields must be indexed in order to sort by them.
33  ///
34  /// <p/>Created: Feb 11, 2004 1:25:29 PM
35  /// </summary>
36  /// <seealso cref="Sort"></seealso>
37  [Serializable]
38  public class SortField
39  {
40  /// <summary>Sort by document score (relevancy). Sort values are Float and higher
41  /// values are at the front.
42  /// </summary>
43  public const int SCORE = 0;
44 
45  /// <summary>Sort by document number (index order). Sort values are Integer and lower
46  /// values are at the front.
47  /// </summary>
48  public const int DOC = 1;
49 
50  // reserved, in Lucene 2.9, there was a constant: AUTO = 2
51 
52  /// <summary>Sort using term values as Strings. Sort values are String and lower
53  /// values are at the front.
54  /// </summary>
55  public const int STRING = 3;
56 
57  /// <summary>Sort using term values as encoded Integers. Sort values are Integer and
58  /// lower values are at the front.
59  /// </summary>
60  public const int INT = 4;
61 
62  /// <summary>Sort using term values as encoded Floats. Sort values are Float and
63  /// lower values are at the front.
64  /// </summary>
65  public const int FLOAT = 5;
66 
67  /// <summary>Sort using term values as encoded Longs. Sort values are Long and
68  /// lower values are at the front.
69  /// </summary>
70  public const int LONG = 6;
71 
72  /// <summary>Sort using term values as encoded Doubles. Sort values are Double and
73  /// lower values are at the front.
74  /// </summary>
75  public const int DOUBLE = 7;
76 
77  /// <summary>Sort using term values as encoded Shorts. Sort values are Short and
78  /// lower values are at the front.
79  /// </summary>
80  public const int SHORT = 8;
81 
82  /// <summary>Sort using a custom Comparator. Sort values are any Comparable and
83  /// sorting is done according to natural order.
84  /// </summary>
85  public const int CUSTOM = 9;
86 
87  /// <summary>Sort using term values as encoded Bytes. Sort values are Byte and
88  /// lower values are at the front.
89  /// </summary>
90  public const int BYTE = 10;
91 
92  /// <summary>Sort using term values as Strings, but comparing by
93  /// value (using String.compareTo) for all comparisons.
94  /// This is typically slower than <see cref="STRING" />, which
95  /// uses ordinals to do the sorting.
96  /// </summary>
97  public const int STRING_VAL = 11;
98 
99  // IMPLEMENTATION NOTE: the FieldCache.STRING_INDEX is in the same "namespace"
100  // as the above static int values. Any new values must not have the same value
101  // as FieldCache.STRING_INDEX.
102 
103  /// <summary>Represents sorting by document score (relevancy). </summary>
104  public static readonly SortField FIELD_SCORE = new SortField(null, SCORE);
105 
106  /// <summary>Represents sorting by document number (index order). </summary>
107  public static readonly SortField FIELD_DOC = new SortField(null, DOC);
108 
109  private System.String field;
110  private int type; // defaults to determining type dynamically
111  private System.Globalization.CultureInfo locale; // defaults to "natural order" (no Locale)
112  internal bool reverse = false; // defaults to natural order
113  private Lucene.Net.Search.Parser parser;
114 
115  // Used for CUSTOM sort
116  private FieldComparatorSource comparatorSource;
117 
118  /// <summary>Creates a sort by terms in the given field with the type of term
119  /// values explicitly given.
120  /// </summary>
121  /// <param name="field"> Name of field to sort by. Can be <c>null</c> if
122  /// <c>type</c> is SCORE or DOC.
123  /// </param>
124  /// <param name="type"> Type of values in the terms.
125  /// </param>
126  public SortField(System.String field, int type)
127  {
128  InitFieldType(field, type);
129  }
130 
131  /// <summary>Creates a sort, possibly in reverse, by terms in the given field with the
132  /// type of term values explicitly given.
133  /// </summary>
134  /// <param name="field"> Name of field to sort by. Can be <c>null</c> if
135  /// <c>type</c> is SCORE or DOC.
136  /// </param>
137  /// <param name="type"> Type of values in the terms.
138  /// </param>
139  /// <param name="reverse">True if natural order should be reversed.
140  /// </param>
141  public SortField(System.String field, int type, bool reverse)
142  {
143  InitFieldType(field, type);
144  this.reverse = reverse;
145  }
146 
147  /// <summary>Creates a sort by terms in the given field, parsed
148  /// to numeric values using a custom <see cref="Search.Parser" />.
149  /// </summary>
150  /// <param name="field"> Name of field to sort by. Must not be null.
151  /// </param>
152  /// <param name="parser">Instance of a <see cref="Search.Parser" />,
153  /// which must subclass one of the existing numeric
154  /// parsers from <see cref="FieldCache" />. Sort type is inferred
155  /// by testing which numeric parser the parser subclasses.
156  /// </param>
157  /// <throws> IllegalArgumentException if the parser fails to </throws>
158  /// <summary> subclass an existing numeric parser, or field is null
159  /// </summary>
160  public SortField(System.String field, Lucene.Net.Search.Parser parser):this(field, parser, false)
161  {
162  }
163 
164  /// <summary>Creates a sort, possibly in reverse, by terms in the given field, parsed
165  /// to numeric values using a custom <see cref="Search.Parser" />.
166  /// </summary>
167  /// <param name="field"> Name of field to sort by. Must not be null.
168  /// </param>
169  /// <param name="parser">Instance of a <see cref="Search.Parser" />,
170  /// which must subclass one of the existing numeric
171  /// parsers from <see cref="FieldCache" />. Sort type is inferred
172  /// by testing which numeric parser the parser subclasses.
173  /// </param>
174  /// <param name="reverse">True if natural order should be reversed.
175  /// </param>
176  /// <throws> IllegalArgumentException if the parser fails to </throws>
177  /// <summary> subclass an existing numeric parser, or field is null
178  /// </summary>
179  public SortField(System.String field, Lucene.Net.Search.Parser parser, bool reverse)
180  {
181  if (parser is Lucene.Net.Search.IntParser)
182  InitFieldType(field, INT);
183  else if (parser is Lucene.Net.Search.FloatParser)
184  InitFieldType(field, FLOAT);
185  else if (parser is Lucene.Net.Search.ShortParser)
186  InitFieldType(field, SHORT);
187  else if (parser is Lucene.Net.Search.ByteParser)
188  InitFieldType(field, BYTE);
189  else if (parser is Lucene.Net.Search.LongParser)
190  InitFieldType(field, LONG);
191  else if (parser is Lucene.Net.Search.DoubleParser)
192  InitFieldType(field, DOUBLE);
193  else
194  {
195  throw new System.ArgumentException("Parser instance does not subclass existing numeric parser from FieldCache (got " + parser + ")");
196  }
197 
198  this.reverse = reverse;
199  this.parser = parser;
200  }
201 
202  /// <summary>Creates a sort by terms in the given field sorted
203  /// according to the given locale.
204  /// </summary>
205  /// <param name="field"> Name of field to sort by, cannot be <c>null</c>.
206  /// </param>
207  /// <param name="locale">Locale of values in the field.
208  /// </param>
209  public SortField(System.String field, System.Globalization.CultureInfo locale)
210  {
211  InitFieldType(field, STRING);
212  this.locale = locale;
213  }
214 
215  /// <summary>Creates a sort, possibly in reverse, by terms in the given field sorted
216  /// according to the given locale.
217  /// </summary>
218  /// <param name="field"> Name of field to sort by, cannot be <c>null</c>.
219  /// </param>
220  /// <param name="locale">Locale of values in the field.
221  /// </param>
222  public SortField(System.String field, System.Globalization.CultureInfo locale, bool reverse)
223  {
224  InitFieldType(field, STRING);
225  this.locale = locale;
226  this.reverse = reverse;
227  }
228 
229  /// <summary>Creates a sort with a custom comparison function.</summary>
230  /// <param name="field">Name of field to sort by; cannot be <c>null</c>.
231  /// </param>
232  /// <param name="comparator">Returns a comparator for sorting hits.
233  /// </param>
234  public SortField(System.String field, FieldComparatorSource comparator)
235  {
236  InitFieldType(field, CUSTOM);
237  this.comparatorSource = comparator;
238  }
239 
240  /// <summary>Creates a sort, possibly in reverse, with a custom comparison function.</summary>
241  /// <param name="field">Name of field to sort by; cannot be <c>null</c>.
242  /// </param>
243  /// <param name="comparator">Returns a comparator for sorting hits.
244  /// </param>
245  /// <param name="reverse">True if natural order should be reversed.
246  /// </param>
247  public SortField(System.String field, FieldComparatorSource comparator, bool reverse)
248  {
249  InitFieldType(field, CUSTOM);
250  this.reverse = reverse;
251  this.comparatorSource = comparator;
252  }
253 
254  // Sets field & type, and ensures field is not NULL unless
255  // type is SCORE or DOC
256  private void InitFieldType(System.String field, int type)
257  {
258  this.type = type;
259  if (field == null)
260  {
261  if (type != SCORE && type != DOC)
262  throw new System.ArgumentException("field can only be null when type is SCORE or DOC");
263  }
264  else
265  {
266  this.field = StringHelper.Intern(field);
267  }
268  }
269 
270  /// <summary>Returns the name of the field. Could return <c>null</c>
271  /// if the sort is by SCORE or DOC.
272  /// </summary>
273  /// <value> Name of field, possibly &lt;c&gt;null&lt;/c&gt;. </value>
274  public virtual string Field
275  {
276  get { return field; }
277  }
278 
279  /// <summary>Returns the type of contents in the field.</summary>
280  /// <value> One of the constants SCORE, DOC, STRING, INT or FLOAT. </value>
281  public virtual int Type
282  {
283  get { return type; }
284  }
285 
286  /// <summary>Returns the Locale by which term values are interpreted.
287  /// May return <c>null</c> if no Locale was specified.
288  /// </summary>
289  /// <value> Locale, or &lt;c&gt;null&lt;/c&gt;. </value>
290  public virtual CultureInfo Locale
291  {
292  get { return locale; }
293  }
294 
295  /// <summary>Returns the instance of a <see cref="FieldCache" /> parser that fits to the given sort type.
296  /// May return <c>null</c> if no parser was specified. Sorting is using the default parser then.
297  /// </summary>
298  /// <value> An instance of a &lt;see cref=&quot;FieldCache&quot; /&gt; parser, or &lt;c&gt;null&lt;/c&gt;. </value>
299  public virtual Parser Parser
300  {
301  get { return parser; }
302  }
303 
304  /// <summary>Returns whether the sort should be reversed.</summary>
305  /// <value> True if natural order should be reversed. </value>
306  public virtual bool Reverse
307  {
308  get { return reverse; }
309  }
310 
311  /// <summary>
312  /// Returns the <see cref="FieldComparatorSource"/> used for
313  /// custom sorting
314  /// </summary>
315  public virtual FieldComparatorSource ComparatorSource
316  {
317  get { return comparatorSource; }
318  }
319 
320  public override System.String ToString()
321  {
322  System.Text.StringBuilder buffer = new System.Text.StringBuilder();
323  switch (type)
324  {
325 
326  case SCORE:
327  buffer.Append("<score>");
328  break;
329 
330  case DOC:
331  buffer.Append("<doc>");
332  break;
333 
334  case STRING:
335  buffer.Append("<string: \"").Append(field).Append("\">");
336  break;
337 
338  case STRING_VAL:
339  buffer.Append("<string_val: \"").Append(field).Append("\">");
340  break;
341 
342  case BYTE:
343  buffer.Append("<byte: \"").Append(field).Append("\">");
344  break;
345 
346  case SHORT:
347  buffer.Append("<short: \"").Append(field).Append("\">");
348  break;
349 
350  case INT:
351  buffer.Append("<int: \"").Append(field).Append("\">");
352  break;
353 
354  case LONG:
355  buffer.Append("<long: \"").Append(field).Append("\">");
356  break;
357 
358  case FLOAT:
359  buffer.Append("<float: \"").Append(field).Append("\">");
360  break;
361 
362  case DOUBLE:
363  buffer.Append("<double: \"").Append(field).Append("\">");
364  break;
365 
366  case CUSTOM:
367  buffer.Append("<custom:\"").Append(field).Append("\": ").Append(comparatorSource).Append('>');
368  break;
369 
370  default:
371  buffer.Append("<???: \"").Append(field).Append("\">");
372  break;
373 
374  }
375 
376  if (locale != null)
377  buffer.Append('(').Append(locale).Append(')');
378  if (parser != null)
379  buffer.Append('(').Append(parser).Append(')');
380  if (reverse)
381  buffer.Append('!');
382 
383  return buffer.ToString();
384  }
385 
386  /// <summary>Returns true if <c>o</c> is equal to this. If a
387  /// <see cref="FieldComparatorSource" /> or <see cref="Search.Parser" />
388  /// was provided, it must properly
389  /// implement equals (unless a singleton is always used).
390  /// </summary>
391  public override bool Equals(System.Object o)
392  {
393  if (this == o)
394  return true;
395  if (!(o is SortField))
396  return false;
397  SortField other = (SortField) o;
398  return ((System.Object) other.field == (System.Object) this.field && other.type == this.type &&
399  other.reverse == this.reverse &&
400  (other.locale == null ? this.locale == null : other.locale.Equals(this.locale)) &&
401  (other.comparatorSource == null
402  ? this.comparatorSource == null
403  : other.comparatorSource.Equals(this.comparatorSource)) &&
404  (other.parser == null ? this.parser == null : other.parser.Equals(this.parser)));
405  }
406 
407  /// <summary>Returns true if <c>o</c> is equal to this. If a
408  /// <see cref="FieldComparatorSource" /> (deprecated) or <see cref="Search.Parser" />
409  /// was provided, it must properly
410  /// implement hashCode (unless a singleton is always
411  /// used).
412  /// </summary>
413  public override int GetHashCode()
414  {
415  int hash = type ^ 0x346565dd + (reverse ? Boolean.TrueString.GetHashCode() : Boolean.FalseString.GetHashCode()) ^ unchecked((int) 0xaf5998bb);
416  if (field != null)
417  hash += (field.GetHashCode() ^ unchecked((int) 0xff5685dd));
418  if (locale != null)
419  {
420  hash += (locale.GetHashCode() ^ 0x08150815);
421  }
422  if (comparatorSource != null)
423  hash += comparatorSource.GetHashCode();
424  if (parser != null)
425  hash += (parser.GetHashCode() ^ 0x3aaf56ff);
426  return hash;
427  }
428 
429 
430  //// field must be interned after reading from stream
431  // private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
432  // in.defaultReadObject();
433  // if (field != null)
434  // field = StringHelper.intern(field);
435  // }
436 
437  [System.Runtime.Serialization.OnDeserialized]
438  internal void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
439  {
440  field = StringHelper.Intern(field);
441  }
442 
443  /// <summary>Returns the <see cref="FieldComparator" /> to use for
444  /// sorting.
445  ///
446  /// <b>NOTE:</b> This API is experimental and might change in
447  /// incompatible ways in the next release.
448  ///
449  /// </summary>
450  /// <param name="numHits">number of top hits the queue will store
451  /// </param>
452  /// <param name="sortPos">position of this SortField within <see cref="Sort" />
453  ///. The comparator is primary if sortPos==0,
454  /// secondary if sortPos==1, etc. Some comparators can
455  /// optimize themselves when they are the primary sort.
456  /// </param>
457  /// <returns> <see cref="FieldComparator" /> to use when sorting
458  /// </returns>
459  public virtual FieldComparator GetComparator(int numHits, int sortPos)
460  {
461 
462  if (locale != null)
463  {
464  // TODO: it'd be nice to allow FieldCache.getStringIndex
465  // to optionally accept a Locale so sorting could then use
466  // the faster StringComparator impls
467  return new FieldComparator.StringComparatorLocale(numHits, field, locale);
468  }
469 
470  switch (type)
471  {
472  case SortField.SCORE:
473  return new FieldComparator.RelevanceComparator(numHits);
474 
475  case SortField.DOC:
476  return new FieldComparator.DocComparator(numHits);
477 
478  case SortField.INT:
479  return new FieldComparator.IntComparator(numHits, field, parser);
480 
481  case SortField.FLOAT:
482  return new FieldComparator.FloatComparator(numHits, field, parser);
483 
484  case SortField.LONG:
485  return new FieldComparator.LongComparator(numHits, field, parser);
486 
487  case SortField.DOUBLE:
488  return new FieldComparator.DoubleComparator(numHits, field, parser);
489 
490  case SortField.BYTE:
491  return new FieldComparator.ByteComparator(numHits, field, parser);
492 
493  case SortField.SHORT:
494  return new FieldComparator.ShortComparator(numHits, field, parser);
495 
496  case SortField.CUSTOM:
497  System.Diagnostics.Debug.Assert(comparatorSource != null);
498  return comparatorSource.NewComparator(field, numHits, sortPos, reverse);
499 
500  case SortField.STRING:
501  return new FieldComparator.StringOrdValComparator(numHits, field, sortPos, reverse);
502 
503  case SortField.STRING_VAL:
504  return new FieldComparator.StringValComparator(numHits, field);
505 
506  default:
507  throw new System.SystemException("Illegal sort type: " + type);
508 
509  }
510  }
511  }
512 }