/*
 * 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.
 */
package org.apache.lucene.search;


import java.io.IOException;
import java.util.Comparator;
import java.util.Objects;

import org.apache.lucene.util.BytesRef;

Stores information about how to sort documents by terms in an individual field. Fields must be indexed in order to sort by them.

Created: Feb 11, 2004 1:25:29 PM

See Also:
Since: lucene 1.4
/** * Stores information about how to sort documents by terms in an individual * field. Fields must be indexed in order to sort by them. * * <p>Created: Feb 11, 2004 1:25:29 PM * * @since lucene 1.4 * @see Sort */
public class SortField {
Specifies the type of the terms to be sorted, or special types such as CUSTOM
/** * Specifies the type of the terms to be sorted, or special types such as CUSTOM */
public static enum Type {
Sort by document score (relevance). Sort values are Float and higher values are at the front.
/** Sort by document score (relevance). Sort values are Float and higher * values are at the front. */
SCORE,
Sort by document number (index order). Sort values are Integer and lower values are at the front.
/** Sort by document number (index order). Sort values are Integer and lower * values are at the front. */
DOC,
Sort using term values as Strings. Sort values are String and lower values are at the front.
/** Sort using term values as Strings. Sort values are String and lower * values are at the front. */
STRING,
Sort using term values as encoded Integers. Sort values are Integer and lower values are at the front.
/** Sort using term values as encoded Integers. Sort values are Integer and * lower values are at the front. */
INT,
Sort using term values as encoded Floats. Sort values are Float and lower values are at the front.
/** Sort using term values as encoded Floats. Sort values are Float and * lower values are at the front. */
FLOAT,
Sort using term values as encoded Longs. Sort values are Long and lower values are at the front.
/** Sort using term values as encoded Longs. Sort values are Long and * lower values are at the front. */
LONG,
Sort using term values as encoded Doubles. Sort values are Double and lower values are at the front.
/** Sort using term values as encoded Doubles. Sort values are Double and * lower values are at the front. */
DOUBLE,
Sort using a custom Comparator. Sort values are any Comparable and sorting is done according to natural order.
/** Sort using a custom Comparator. Sort values are any Comparable and * sorting is done according to natural order. */
CUSTOM,
Sort using term values as Strings, but comparing by value (using String.compareTo) for all comparisons. This is typically slower than STRING, which uses ordinals to do the sorting.
/** Sort using term values as Strings, but comparing by * value (using String.compareTo) for all comparisons. * This is typically slower than {@link #STRING}, which * uses ordinals to do the sorting. */
STRING_VAL,
Force rewriting of SortField using SortField.rewrite(IndexSearcher) before it can be used for sorting
/** Force rewriting of SortField using {@link SortField#rewrite(IndexSearcher)} * before it can be used for sorting */
REWRITEABLE }
Represents sorting by document score (relevance).
/** Represents sorting by document score (relevance). */
public static final SortField FIELD_SCORE = new SortField(null, Type.SCORE);
Represents sorting by document number (index order).
/** Represents sorting by document number (index order). */
public static final SortField FIELD_DOC = new SortField(null, Type.DOC); private String field; private Type type; // defaults to determining type dynamically boolean reverse = false; // defaults to natural order // Used for CUSTOM sort private FieldComparatorSource comparatorSource; // Used for 'sortMissingFirst/Last' protected Object missingValue = null;
Creates a sort by terms in the given field with the type of term values explicitly given.
Params:
  • field – Name of field to sort by. Can be null if type is SCORE or DOC.
  • type – Type of values in the terms.
/** Creates a sort by terms in the given field with the type of term * values explicitly given. * @param field Name of field to sort by. Can be <code>null</code> if * <code>type</code> is SCORE or DOC. * @param type Type of values in the terms. */
public SortField(String field, Type type) { initFieldType(field, type); }
Creates a sort, possibly in reverse, by terms in the given field with the type of term values explicitly given.
Params:
  • field – Name of field to sort by. Can be null if type is SCORE or DOC.
  • type – Type of values in the terms.
  • reverse – True if natural order should be reversed.
/** Creates a sort, possibly in reverse, by terms in the given field with the * type of term values explicitly given. * @param field Name of field to sort by. Can be <code>null</code> if * <code>type</code> is SCORE or DOC. * @param type Type of values in the terms. * @param reverse True if natural order should be reversed. */
public SortField(String field, Type type, boolean reverse) { initFieldType(field, type); this.reverse = reverse; }
Pass this to setMissingValue to have missing string values sort first.
/** Pass this to {@link #setMissingValue} to have missing * string values sort first. */
public final static Object STRING_FIRST = new Object() { @Override public String toString() { return "SortField.STRING_FIRST"; } };
Pass this to setMissingValue to have missing string values sort last.
/** Pass this to {@link #setMissingValue} to have missing * string values sort last. */
public final static Object STRING_LAST = new Object() { @Override public String toString() { return "SortField.STRING_LAST"; } };
Return the value to use for documents that don't have a value. A value of null indicates that default should be used.
/** Return the value to use for documents that don't have a value. * A value of {@code null} indicates that default should be used. */
public Object getMissingValue() { return missingValue; }
Set the value to use for documents that don't have a value.
/** Set the value to use for documents that don't have a value. */
public void setMissingValue(Object missingValue) { if (type == Type.STRING || type == Type.STRING_VAL) { if (missingValue != STRING_FIRST && missingValue != STRING_LAST) { throw new IllegalArgumentException("For STRING type, missing value must be either STRING_FIRST or STRING_LAST"); } } else if (type == Type.INT) { if (missingValue != null && missingValue.getClass() != Integer.class) throw new IllegalArgumentException("Missing values for Type.INT can only be of type java.lang.Integer, but got " + missingValue.getClass()); } else if (type == Type.LONG) { if (missingValue != null && missingValue.getClass() != Long.class) throw new IllegalArgumentException("Missing values for Type.LONG can only be of type java.lang.Long, but got " + missingValue.getClass()); } else if (type == Type.FLOAT) { if (missingValue != null && missingValue.getClass() != Float.class) throw new IllegalArgumentException("Missing values for Type.FLOAT can only be of type java.lang.Float, but got " + missingValue.getClass()); } else if (type == Type.DOUBLE) { if (missingValue != null && missingValue.getClass() != Double.class) throw new IllegalArgumentException("Missing values for Type.DOUBLE can only be of type java.lang.Double, but got " + missingValue.getClass()); } else { throw new IllegalArgumentException("Missing value only works for numeric or STRING types"); } this.missingValue = missingValue; }
Creates a sort with a custom comparison function.
Params:
  • field – Name of field to sort by; cannot be null.
  • comparator – Returns a comparator for sorting hits.
/** Creates a sort with a custom comparison function. * @param field Name of field to sort by; cannot be <code>null</code>. * @param comparator Returns a comparator for sorting hits. */
public SortField(String field, FieldComparatorSource comparator) { initFieldType(field, Type.CUSTOM); this.comparatorSource = comparator; }
Creates a sort, possibly in reverse, with a custom comparison function.
Params:
  • field – Name of field to sort by; cannot be null.
  • comparator – Returns a comparator for sorting hits.
  • reverse – True if natural order should be reversed.
/** Creates a sort, possibly in reverse, with a custom comparison function. * @param field Name of field to sort by; cannot be <code>null</code>. * @param comparator Returns a comparator for sorting hits. * @param reverse True if natural order should be reversed. */
public SortField(String field, FieldComparatorSource comparator, boolean reverse) { initFieldType(field, Type.CUSTOM); this.reverse = reverse; this.comparatorSource = comparator; } // Sets field & type, and ensures field is not NULL unless // type is SCORE or DOC private void initFieldType(String field, Type type) { this.type = type; if (field == null) { if (type != Type.SCORE && type != Type.DOC) { throw new IllegalArgumentException("field can only be null when type is SCORE or DOC"); } } else { this.field = field; } }
Returns the name of the field. Could return null if the sort is by SCORE or DOC.
Returns:Name of field, possibly null.
/** Returns the name of the field. Could return <code>null</code> * if the sort is by SCORE or DOC. * @return Name of field, possibly <code>null</code>. */
public String getField() { return field; }
Returns the type of contents in the field.
Returns:One of the constants SCORE, DOC, STRING, INT or FLOAT.
/** Returns the type of contents in the field. * @return One of the constants SCORE, DOC, STRING, INT or FLOAT. */
public Type getType() { return type; }
Returns whether the sort should be reversed.
Returns: True if natural order should be reversed.
/** Returns whether the sort should be reversed. * @return True if natural order should be reversed. */
public boolean getReverse() { return reverse; }
Returns the FieldComparatorSource used for custom sorting
/** Returns the {@link FieldComparatorSource} used for * custom sorting */
public FieldComparatorSource getComparatorSource() { return comparatorSource; } @Override public String toString() { StringBuilder buffer = new StringBuilder(); switch (type) { case SCORE: buffer.append("<score>"); break; case DOC: buffer.append("<doc>"); break; case STRING: buffer.append("<string" + ": \"").append(field).append("\">"); break; case STRING_VAL: buffer.append("<string_val" + ": \"").append(field).append("\">"); break; case INT: buffer.append("<int" + ": \"").append(field).append("\">"); break; case LONG: buffer.append("<long: \"").append(field).append("\">"); break; case FLOAT: buffer.append("<float" + ": \"").append(field).append("\">"); break; case DOUBLE: buffer.append("<double" + ": \"").append(field).append("\">"); break; case CUSTOM: buffer.append("<custom:\"").append(field).append("\": ").append(comparatorSource).append('>'); break; case REWRITEABLE: buffer.append("<rewriteable: \"").append(field).append("\">"); break; default: buffer.append("<???: \"").append(field).append("\">"); break; } if (reverse) buffer.append('!'); if (missingValue != null) { buffer.append(" missingValue="); buffer.append(missingValue); } return buffer.toString(); }
Returns true if o is equal to this. If a FieldComparatorSource was provided, it must properly implement equals (unless a singleton is always used).
/** Returns true if <code>o</code> is equal to this. If a * {@link FieldComparatorSource} was provided, it must properly * implement equals (unless a singleton is always used). */
@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof SortField)) return false; final SortField other = (SortField)o; return ( Objects.equals(other.field, this.field) && other.type == this.type && other.reverse == this.reverse && Objects.equals(this.comparatorSource, other.comparatorSource) && Objects.equals(this.missingValue, other.missingValue) ); }
Returns a hash code for this SortField instance. If a FieldComparatorSource was provided, it must properly implement hashCode (unless a singleton is always used).
/** Returns a hash code for this {@link SortField} instance. If a * {@link FieldComparatorSource} was provided, it must properly * implement hashCode (unless a singleton is always used). */
@Override public int hashCode() { return Objects.hash(field, type, reverse, comparatorSource, missingValue); } private Comparator<BytesRef> bytesComparator = Comparator.naturalOrder(); public void setBytesComparator(Comparator<BytesRef> b) { bytesComparator = b; } public Comparator<BytesRef> getBytesComparator() { return bytesComparator; }
Returns the FieldComparator to use for sorting.
Params:
  • numHits – number of top hits the queue will store
  • sortPos – position of this SortField within Sort. The comparator is primary if sortPos==0, secondary if sortPos==1, etc. Some comparators can optimize themselves when they are the primary sort.
@lucene.experimental
Returns:FieldComparator to use when sorting
/** Returns the {@link FieldComparator} to use for * sorting. * * @lucene.experimental * * @param numHits number of top hits the queue will store * @param sortPos position of this SortField within {@link * Sort}. The comparator is primary if sortPos==0, * secondary if sortPos==1, etc. Some comparators can * optimize themselves when they are the primary sort. * @return {@link FieldComparator} to use when sorting */
public FieldComparator<?> getComparator(final int numHits, final int sortPos) { switch (type) { case SCORE: return new FieldComparator.RelevanceComparator(numHits); case DOC: return new FieldComparator.DocComparator(numHits); case INT: return new FieldComparator.IntComparator(numHits, field, (Integer) missingValue); case FLOAT: return new FieldComparator.FloatComparator(numHits, field, (Float) missingValue); case LONG: return new FieldComparator.LongComparator(numHits, field, (Long) missingValue); case DOUBLE: return new FieldComparator.DoubleComparator(numHits, field, (Double) missingValue); case CUSTOM: assert comparatorSource != null; return comparatorSource.newComparator(field, numHits, sortPos, reverse); case STRING: return new FieldComparator.TermOrdValComparator(numHits, field, missingValue == STRING_LAST); case STRING_VAL: return new FieldComparator.TermValComparator(numHits, field, missingValue == STRING_LAST); case REWRITEABLE: throw new IllegalStateException("SortField needs to be rewritten through Sort.rewrite(..) and SortField.rewrite(..)"); default: throw new IllegalStateException("Illegal sort type: " + type); } }
Rewrites this SortField, returning a new SortField if a change is made. Subclasses should override this define their rewriting behavior when this SortField is of type Type.REWRITEABLE
Params:
  • searcher – IndexSearcher to use during rewriting
Throws:
Returns:New rewritten SortField, or this if nothing has changed.
@lucene.experimental
/** * Rewrites this SortField, returning a new SortField if a change is made. * Subclasses should override this define their rewriting behavior when this * SortField is of type {@link SortField.Type#REWRITEABLE} * * @param searcher IndexSearcher to use during rewriting * @return New rewritten SortField, or {@code this} if nothing has changed. * @throws IOException Can be thrown by the rewriting * @lucene.experimental */
public SortField rewrite(IndexSearcher searcher) throws IOException { return this; }
Whether the relevance score is needed to sort documents.
/** Whether the relevance score is needed to sort documents. */
public boolean needsScores() { return type == Type.SCORE; } }