Index: lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java =================================================================== --- lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java (revision 1466166) +++ lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java (working copy) @@ -24,37 +24,58 @@ /** * A {@link Sorter} which sorts documents according to their - * {@link NumericDocValues}. - * + * {@link NumericDocValues}. One can specify ascending or descending sort order. + * * @lucene.experimental */ public class NumericDocValuesSorter extends Sorter { private final String fieldName; - + private final boolean ascending; + + /** Constructor over the given field name, and ascending sort order. */ public NumericDocValuesSorter(final String fieldName) { + this(fieldName, true); + } + + /** + * Constructor over the given field name, and whether sorting should be + * ascending ({@code true}) or descending ({@code false}). + */ + public NumericDocValuesSorter(final String fieldName, boolean ascending) { this.fieldName = fieldName; + this.ascending = ascending; } @Override public Sorter.DocMap sort(final AtomicReader reader) throws IOException { final NumericDocValues ndv = reader.getNumericDocValues(fieldName); - final DocComparator comparator = new DocComparator() { - - @Override - public int compare(int docID1, int docID2) { - final long v1 = ndv.get(docID1); - final long v2 = ndv.get(docID2); - return v1 < v2 ? -1 : v1 == v2 ? 0 : 1; - } - - }; + final DocComparator comparator; + if (ascending) { + comparator = new DocComparator() { + @Override + public int compare(int docID1, int docID2) { + final long v1 = ndv.get(docID1); + final long v2 = ndv.get(docID2); + return v1 < v2 ? -1 : v1 == v2 ? 0 : 1; + } + }; + } else { + comparator = new DocComparator() { + @Override + public int compare(int docID1, int docID2) { + final long v1 = ndv.get(docID1); + final long v2 = ndv.get(docID2); + return v1 > v2 ? -1 : v1 == v2 ? 0 : 1; + } + }; + } return sort(reader.maxDoc(), comparator); } @Override public String getID() { - return "DocValues(" + fieldName + ",asc)"; + return "DocValues(" + fieldName + "," + (ascending ? "ascending" : "descending") + ")"; } } Index: lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java =================================================================== --- lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java (revision 1466166) +++ lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java (working copy) @@ -81,6 +81,47 @@ } + /** Sorts documents in reverse order of a wrapped {@link Sorter}. */ + public static final class ReverseOrderSorter extends Sorter { + + private final Sorter in; + + public ReverseOrderSorter(Sorter in) { + if (in == REVERSE_DOCS || in instanceof ReverseOrderSorter) { + throw new IllegalArgumentException("reversing the order of a reversing sorter doesn't make any sense!"); + } + this.in = in; + } + + @Override + public DocMap sort(final AtomicReader reader) throws IOException { + final int maxDoc = reader.maxDoc(); + final DocMap inMap = in.sort(reader); + return new DocMap() { + @Override + public int oldToNew(int docID) { + return maxDoc - inMap.oldToNew(docID) - 1; + } + + @Override + public int newToOld(int docID) { + return inMap.newToOld(maxDoc - docID -1); + } + + @Override + public int size() { + return inMap.size(); + } + + }; + } + + @Override + public String getID() { + return "Reverse(" + in.getID() + ")"; + } + } + /** Sorts documents in reverse order. * NOTE: This {@link Sorter} is not idempotent. Sorting an * {@link AtomicReader} once or twice will return two different @@ -111,7 +152,7 @@ return "ReverseDocs"; } }; - + private static final class DocValueSorterTemplate extends SorterTemplate { private final int[] docs; @@ -231,4 +272,9 @@ */ public abstract String getID(); + @Override + public String toString() { + return getID(); + } + } Index: lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java =================================================================== --- lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java (revision 1466166) +++ lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java (working copy) @@ -32,7 +32,7 @@ public class IndexSortingTest extends SorterTestBase { private static final Sorter[] SORTERS = new Sorter[] { - new NumericDocValuesSorter(NUMERIC_DV_FIELD), + new NumericDocValuesSorter(NUMERIC_DV_FIELD, true), Sorter.REVERSE_DOCS, }; @@ -52,6 +52,13 @@ Collections.reverse(values); } else { Collections.sort(values); + if (sorter instanceof NumericDocValuesSorter && random().nextBoolean()) { + sorter = new NumericDocValuesSorter(NUMERIC_DV_FIELD, false); // descending + Collections.reverse(values); + } else if (random().nextBoolean()) { // wrap with reverse order + sorter = new Sorter.ReverseOrderSorter(sorter); + Collections.reverse(values); + } } sortedValues = values.toArray(new Integer[values.size()]); if (VERBOSE) {