blob: 55e6b75b913d00103b369be2d24edb14f4664f37 [file] [log] [blame]
using Lucene.Net.Support;
using System.IO;
using System.Text;
namespace Lucene.Net.Search
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <summary>
/// Encapsulates sort criteria for returned hits.
///
/// <para/>The fields used to determine sort order must be carefully chosen.
/// <see cref="Documents.Document"/>s must contain a single term in such a field,
/// and the value of the term should indicate the document's relative position in
/// a given sort order. The field must be indexed, but should not be tokenized,
/// and does not need to be stored (unless you happen to want it back with the
/// rest of your document data). In other words:
///
/// <para/><code>document.Add(new Field("byNumber", x.ToString(CultureInfo.InvariantCulture), Field.Store.NO, Field.Index.NOT_ANALYZED));</code>
///
///
/// <para/><h3>Valid Types of Values</h3>
///
/// <para/>There are four possible kinds of term values which may be put into
/// sorting fields: <see cref="int"/>s, <see cref="long"/>s, <see cref="float"/>s, or <see cref="string"/>s. Unless
/// <see cref="SortField"/> objects are specified, the type of value
/// in the field is determined by parsing the first term in the field.
///
/// <para/><see cref="int"/> term values should contain only digits and an optional
/// preceding negative sign. Values must be base 10 and in the range
/// <see cref="int.MinValue"/> and <see cref="int.MaxValue"/> inclusive.
/// Documents which should appear first in the sort
/// should have low value integers, later documents high values
/// (i.e. the documents should be numbered <c>1..n</c> where
/// <c>1</c> is the first and <c>n</c> the last).
///
/// <para/><see cref="long"/> term values should contain only digits and an optional
/// preceding negative sign. Values must be base 10 and in the range
/// <see cref="long.MinValue"/> and <see cref="long.MaxValue"/> inclusive.
/// Documents which should appear first in the sort
/// should have low value integers, later documents high values.
///
/// <para/><see cref="float"/> term values should conform to values accepted by
/// <see cref="float"/> (except that <c>NaN</c>
/// and <c>Infinity</c> are not supported).
/// <see cref="Documents.Document"/>s which should appear first in the sort
/// should have low values, later documents high values.
///
/// <para/><see cref="string"/> term values can contain any valid <see cref="string"/>, but should
/// not be tokenized. The values are sorted according to their
/// comparable natural order (<see cref="System.StringComparer.Ordinal"/>). Note that using this type
/// of term value has higher memory requirements than the other
/// two types.
///
/// <para/><h3>Object Reuse</h3>
///
/// <para/>One of these objects can be
/// used multiple times and the sort order changed between usages.
///
/// <para/>This class is thread safe.
///
/// <para/><h3>Memory Usage</h3>
///
/// <para/>Sorting uses of caches of term values maintained by the
/// internal HitQueue(s). The cache is static and contains an <see cref="int"/>
/// or <see cref="float"/> array of length <c>IndexReader.MaxDoc</c> for each field
/// name for which a sort is performed. In other words, the size of the
/// cache in bytes is:
///
/// <para/><code>4 * IndexReader.MaxDoc * (# of different fields actually used to sort)</code>
///
/// <para/>For <see cref="string"/> fields, the cache is larger: in addition to the
/// above array, the value of every term in the field is kept in memory.
/// If there are many unique terms in the field, this could
/// be quite large.
///
/// <para/>Note that the size of the cache is not affected by how many
/// fields are in the index and <i>might</i> be used to sort - only by
/// the ones actually used to sort a result set.
///
/// <para/>Created: Feb 12, 2004 10:53:57 AM
/// <para/>
/// @since lucene 1.4
/// </summary>
public class Sort
{
/// <summary>
/// Represents sorting by computed relevance. Using this sort criteria returns
/// the same results as calling
/// <see cref="IndexSearcher.Search(Query, int)"/>without a sort criteria,
/// only with slightly more overhead.
/// </summary>
public static readonly Sort RELEVANCE = new Sort();
/// <summary>
/// Represents sorting by index order. </summary>
public static readonly Sort INDEXORDER = new Sort(SortField.FIELD_DOC);
// internal representation of the sort criteria
internal SortField[] fields;
/// <summary>
/// Sorts by computed relevance. This is the same sort criteria as calling
/// <see cref="IndexSearcher.Search(Query, int)"/> without a sort criteria,
/// only with slightly more overhead.
/// </summary>
public Sort()
: this(SortField.FIELD_SCORE)
{
}
/// <summary>
/// Sorts by the criteria in the given <see cref="SortField"/>. </summary>
public Sort(SortField field)
{
SetSort(field);
}
/// <summary>
/// Sorts in succession by the criteria in each <see cref="SortField"/>. </summary>
public Sort(params SortField[] fields)
{
SetSort(fields);
}
/// <summary>Sets the sort to the given criteria. </summary>
public virtual void SetSort(SortField field)
{
this.fields = new SortField[] { field };
}
/// <summary>Sets the sort to the given criteria in succession. </summary>
public virtual void SetSort(params SortField[] fields)
{
this.fields = fields;
}
/// <summary> Representation of the sort criteria.</summary>
/// <returns> Array of <see cref="SortField"/> objects used in this sort criteria
/// </returns>
[WritableArray]
public virtual SortField[] GetSort()
{
return fields;
}
/// <summary>
/// Rewrites the <see cref="SortField"/>s in this <see cref="Sort"/>, returning a new <see cref="Sort"/> if any of the fields
/// changes during their rewriting.
/// <para/>
/// @lucene.experimental
/// </summary>
/// <param name="searcher"> <see cref="IndexSearcher"/> to use in the rewriting </param>
/// <returns> <c>this</c> if the Sort/Fields have not changed, or a new <see cref="Sort"/> if there
/// is a change </returns>
/// <exception cref="IOException"> Can be thrown by the rewriting</exception>
public virtual Sort Rewrite(IndexSearcher searcher)
{
bool changed = false;
SortField[] rewrittenSortFields = new SortField[fields.Length];
for (int i = 0; i < fields.Length; i++)
{
rewrittenSortFields[i] = fields[i].Rewrite(searcher);
if (fields[i] != rewrittenSortFields[i])
{
changed = true;
}
}
return (changed) ? new Sort(rewrittenSortFields) : this;
}
public override string ToString()
{
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < fields.Length; i++)
{
buffer.Append(fields[i].ToString());
if ((i + 1) < fields.Length)
{
buffer.Append(',');
}
}
return buffer.ToString();
}
/// <summary>
/// Returns <c>true</c> if <paramref name="o"/> is equal to this. </summary>
public override bool Equals(object o)
{
if (this == o)
{
return true;
}
if (!(o is Sort))
{
return false;
}
Sort other = (Sort)o;
return Arrays.Equals(this.fields, other.fields);
}
/// <summary>
/// Returns a hash code value for this object. </summary>
public override int GetHashCode()
{
return 0x45aaf665 + Arrays.GetHashCode(fields);
}
/// <summary>
/// Returns <c>true</c> if the relevance score is needed to sort documents. </summary>
public virtual bool NeedsScores
{
get
{
foreach (SortField sortField in fields)
{
if (sortField.NeedsScores)
{
return true;
}
}
return false;
}
}
}
}