/* * 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 org.apache.lucene.index.DocValues; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedSetDocValues; /** * SortField for {@link SortedSetDocValues}. * <p> * A SortedSetDocValues contains multiple values for a field, so sorting with * this technique "selects" a value as the representative sort value for the document. * <p> * By default, the minimum value in the set is selected as the sort value, but * this can be customized. Selectors other than the default do have some limitations * to ensure that all selections happen in constant-time for performance. * <p> * Like sorting by string, this also supports sorting missing values as first or last, * via {@link #setMissingValue(Object)}. * @see SortedSetSelector */ public class SortedSetSortField extends SortField { private final SortedSetSelector.Type selector; /** * Creates a sort, possibly in reverse, by the minimum value in the set * for the document. * @param field Name of field to sort by. Must not be null. * @param reverse True if natural order should be reversed. */ public SortedSetSortField(String field, boolean reverse) { this(field, reverse, SortedSetSelector.Type.MIN); } /** * Creates a sort, possibly in reverse, specifying how the sort value from * the document's set is selected. * @param field Name of field to sort by. Must not be null. * @param reverse True if natural order should be reversed. * @param selector custom selector type for choosing the sort value from the set. * <p> * NOTE: selectors other than {@link SortedSetSelector.Type#MIN} require optional codec support. */ public SortedSetSortField(String field, boolean reverse, SortedSetSelector.Type selector) { super(field, SortField.Type.CUSTOM, reverse); if (selector == null) { throw new NullPointerException(); } this.selector = selector; } /** Returns the selector in use for this sort */ public SortedSetSelector.Type getSelector() { return selector; } @Override public int hashCode() { return 31 * super.hashCode() + selector.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; SortedSetSortField other = (SortedSetSortField) obj; if (selector != other.selector) return false; return true; } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("<sortedset" + ": \"").append(getField()).append("\">"); if (getReverse()) buffer.append('!'); if (missingValue != null) { buffer.append(" missingValue="); buffer.append(missingValue); } buffer.append(" selector="); buffer.append(selector); return buffer.toString(); } /** * Set how missing values (the empty set) are sorted. * <p> * Note that this must be {@link #STRING_FIRST} or {@link #STRING_LAST}. */ @Override public void setMissingValue(Object missingValue) { if (missingValue != STRING_FIRST && missingValue != STRING_LAST) { throw new IllegalArgumentException("For SORTED_SET type, missing value must be either STRING_FIRST or STRING_LAST"); } this.missingValue = missingValue; } @Override public FieldComparator<?> getComparator(int numHits, int sortPos) { return new FieldComparator.TermOrdValComparator(numHits, getField(), missingValue == STRING_LAST) { @Override protected SortedDocValues getSortedDocValues(LeafReaderContext context, String field) throws IOException { return SortedSetSelector.wrap(DocValues.getSortedSet(context.reader(), field), selector); } }; } }