From 44ca68f294f915bfce99d62a13a9e60e925bdf9b Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Fri, 15 Mar 2013 07:10:26 +0000 Subject: [PATCH] LUCENE-4830: Sorter API: Make the doc ID mapping an abstract class. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1456787 13f79535-47bb-0310-9956-ffa450edef68 --- .../index/sorter/NumericDocValuesSorter.java | 26 +-- .../apache/lucene/index/sorter/Sorter.java | 148 ++++++++++++++---- .../index/sorter/SortingAtomicReader.java | 147 ++++++++--------- .../lucene/index/sorter/IndexSortingTest.java | 2 +- .../index/sorter/SortingAtomicReaderTest.java | 25 +-- 5 files changed, 219 insertions(+), 129 deletions(-) diff --git a/lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java b/lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java index 84f9616c68b..5b8d40bed5b 100644 --- a/lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java +++ b/lucene/misc/src/java/org/apache/lucene/index/sorter/NumericDocValuesSorter.java @@ -18,8 +18,6 @@ package org.apache.lucene.index.sorter; */ import java.io.IOException; -import java.util.AbstractList; -import java.util.List; import org.apache.lucene.index.AtomicReader; import org.apache.lucene.index.NumericDocValues; @@ -27,7 +25,7 @@ import org.apache.lucene.index.NumericDocValues; /** * A {@link Sorter} which sorts documents according to their * {@link NumericDocValues}. - * + * * @lucene.experimental */ public class NumericDocValuesSorter extends Sorter { @@ -39,27 +37,19 @@ public class NumericDocValuesSorter extends Sorter { } @Override - public int[] oldToNew(final AtomicReader reader) throws IOException { + public Sorter.DocMap sort(final AtomicReader reader) throws IOException { final NumericDocValues ndv = reader.getNumericDocValues(fieldName); - final int maxDoc = reader.maxDoc(); - final int[] docs = new int[maxDoc]; - final List values = new AbstractList() { + final DocComparator comparator = new DocComparator() { @Override - public Long get(int doc) { - return ndv.get(doc); - } - - @Override - public int size() { - return reader.maxDoc(); + 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; } }; - for (int i = 0; i < maxDoc; i++) { - docs[i] = i; - } - return compute(docs, values); + return sort(reader.maxDoc(), comparator); } } diff --git a/lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java b/lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java index 33b61f652cb..89135325ef4 100644 --- a/lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java +++ b/lucene/misc/src/java/org/apache/lucene/index/sorter/Sorter.java @@ -18,58 +18,102 @@ package org.apache.lucene.index.sorter; */ import java.io.IOException; -import java.util.List; +import java.util.Comparator; import org.apache.lucene.index.AtomicReader; +import org.apache.lucene.index.IndexReader; import org.apache.lucene.util.SorterTemplate; +import org.apache.lucene.util.packed.MonotonicAppendingLongBuffer; /** * Sorts documents in a given index by returning a permutation on the docs. - * Implementations can call {@link #compute(int[], List)} to compute the + * Implementations can call {@link #sort(int, DocComparator)} to compute the * old-to-new permutation over the given documents and values. * * @lucene.experimental */ public abstract class Sorter { - + + /** + * A permutation of doc IDs. For every document ID between 0 and + * {@link IndexReader#maxDoc()}, oldToNew(newToOld(docID)) must + * return docID. + */ + public static abstract class DocMap { + + /** Given a doc ID from the original index, return its ordinal in the + * sorted index. */ + public abstract int oldToNew(int docID); + + /** Given the ordinal of a doc ID, return its doc ID in the original index. */ + public abstract int newToOld(int docID); + + } + + /** Check consistency of a {@link DocMap}, useful for assertions. */ + static boolean isConsistent(DocMap docMap, int maxDoc) { + for (int i = 0; i < maxDoc; ++i) { + final int newID = docMap.oldToNew(i); + final int oldID = docMap.newToOld(newID); + assert newID >= 0 && newID < maxDoc : "doc IDs must be in [0-" + maxDoc + "[, got " + newID; + assert i == oldID : "mapping is inconsistent: " + i + " --oldToNew--> " + newID + " --newToOld--> " + oldID; + if (i != oldID || newID < 0 || newID >= maxDoc) { + return false; + } + } + return true; + } + + /** A comparator of doc IDs. */ + public static abstract class DocComparator { + + /** Compare docID1 against docID2. The contract for the return value is the + * same as {@link Comparator#compare(Object, Object)}. */ + public abstract int compare(int docID1, int docID2); + + } + /** Sorts documents in reverse order. */ public static final Sorter REVERSE_DOCS = new Sorter() { @Override - public int[] oldToNew(final AtomicReader reader) throws IOException { + public DocMap sort(final AtomicReader reader) throws IOException { final int maxDoc = reader.maxDoc(); - int[] reverseDocs = new int[maxDoc]; - for (int i = 0; i < maxDoc; i++) { - reverseDocs[i] = maxDoc - (i + 1); - } - return reverseDocs; + return new DocMap() { + public int oldToNew(int docID) { + return maxDoc - docID - 1; + } + public int newToOld(int docID) { + return maxDoc - docID - 1; + } + }; } }; - private static final class DocValueSorterTemplate> extends SorterTemplate { + private static final class DocValueSorterTemplate extends SorterTemplate { private final int[] docs; - private final List values; + private final Sorter.DocComparator comparator; - private T pivot; + private int pivot; - public DocValueSorterTemplate(int[] docs, List values) { + public DocValueSorterTemplate(int[] docs, Sorter.DocComparator comparator) { this.docs = docs; - this.values = values; + this.comparator = comparator; } @Override protected int compare(int i, int j) { - return values.get(docs[i]).compareTo(values.get(docs[j])); + return comparator.compare(docs[i], docs[j]); } @Override protected int comparePivot(int j) { - return pivot.compareTo(values.get(docs[j])); + return comparator.compare(pivot, docs[j]); } @Override protected void setPivot(int i) { - pivot = values.get(docs[i]); + pivot = docs[i]; } @Override @@ -80,27 +124,73 @@ public abstract class Sorter { } } - /** Computes the old-to-new permutation over the given documents and values. */ - protected static > int[] compute(int[] docs, List values) { - SorterTemplate sorter = new DocValueSorterTemplate(docs, values); - sorter.quickSort(0, docs.length - 1); - - final int[] oldToNew = new int[docs.length]; - for (int i = 0; i < docs.length; i++) { - oldToNew[docs[i]] = i; + /** Computes the old-to-new permutation over the given comparator. */ + protected static Sorter.DocMap sort(final int maxDoc, DocComparator comparator) { + // check if the index is sorted + boolean sorted = true; + for (int i = 1; i < maxDoc; ++i) { + if (comparator.compare(i-1, i) > 0) { + sorted = false; + break; + } } - return oldToNew; + if (sorted) { + return null; + } + + // sort doc IDs + final int[] docs = new int[maxDoc]; + for (int i = 0; i < maxDoc; i++) { + docs[i] = i; + } + + SorterTemplate sorter = new DocValueSorterTemplate(docs, comparator); + // TODO: use a stable sort instead? + sorter.quickSort(0, docs.length - 1); // docs is now the newToOld mapping + + // The reason why we use MonotonicAppendingLongBuffer here is that it + // wastes very little memory if the index is in random order but can save + // a lot of memory if the index is already "almost" sorted + final MonotonicAppendingLongBuffer newToOld = new MonotonicAppendingLongBuffer(); + for (int i = 0; i < maxDoc; ++i) { + newToOld.add(docs[i]); + } + + for (int i = 0; i < maxDoc; ++i) { + docs[(int) newToOld.get(i)] = i; + } // docs is now the oldToNew mapping + + final MonotonicAppendingLongBuffer oldToNew = new MonotonicAppendingLongBuffer(); + for (int i = 0; i < maxDoc; ++i) { + oldToNew.add(docs[i]); + } + + return new Sorter.DocMap() { + + @Override + public int oldToNew(int docID) { + return (int) oldToNew.get(docID); + } + + @Override + public int newToOld(int docID) { + return (int) newToOld.get(docID); + } + }; } /** * Returns a mapping from the old document ID to its new location in the * sorted index. Implementations can use the auxiliary - * {@link #compute(int[], List)} to compute the old-to-new permutation - * given an array of documents and their corresponding values. + * {@link #sort(int, DocComparator)} to compute the old-to-new permutation + * given a list of documents and their corresponding values. + *

+ * A return value of null is allowed and means that + * reader is already sorted. *

* NOTE: deleted documents are expected to appear in the mapping as * well, they will however be dropped when the index is actually sorted. */ - public abstract int[] oldToNew(AtomicReader reader) throws IOException; + public abstract DocMap sort(AtomicReader reader) throws IOException; } diff --git a/lucene/misc/src/java/org/apache/lucene/index/sorter/SortingAtomicReader.java b/lucene/misc/src/java/org/apache/lucene/index/sorter/SortingAtomicReader.java index af757a9cbae..87a25a4fdcc 100644 --- a/lucene/misc/src/java/org/apache/lucene/index/sorter/SortingAtomicReader.java +++ b/lucene/misc/src/java/org/apache/lucene/index/sorter/SortingAtomicReader.java @@ -43,7 +43,6 @@ import org.apache.lucene.store.RAMOutputStream; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.SorterTemplate; /** @@ -66,13 +65,13 @@ public class SortingAtomicReader extends FilterAtomicReader { private static class SortingFields extends FilterFields { - private final int[] old2new; + private final Sorter.DocMap docMap; private final Bits inLiveDocs; private final FieldInfos infos; - public SortingFields(final Fields in, final Bits inLiveDocs, FieldInfos infos, final int[] old2new) { + public SortingFields(final Fields in, final Bits inLiveDocs, FieldInfos infos, Sorter.DocMap docMap) { super(in); - this.old2new = old2new; + this.docMap = docMap; this.inLiveDocs = inLiveDocs; this.infos = infos; } @@ -83,7 +82,7 @@ public class SortingAtomicReader extends FilterAtomicReader { if (terms == null) { return null; } else { - return new SortingTerms(terms, inLiveDocs, infos.fieldInfo(field).getIndexOptions(), old2new); + return new SortingTerms(terms, inLiveDocs, infos.fieldInfo(field).getIndexOptions(), docMap); } } @@ -91,33 +90,33 @@ public class SortingAtomicReader extends FilterAtomicReader { private static class SortingTerms extends FilterTerms { - private final int[] old2new; + private final Sorter.DocMap docMap; private final Bits inLiveDocs; private final IndexOptions indexOptions; - public SortingTerms(final Terms in, final Bits inLiveDocs, IndexOptions indexOptions, final int[] old2new) { + public SortingTerms(final Terms in, final Bits inLiveDocs, IndexOptions indexOptions, final Sorter.DocMap docMap) { super(in); - this.old2new = old2new; + this.docMap = docMap; this.inLiveDocs = inLiveDocs; this.indexOptions = indexOptions; } @Override public TermsEnum iterator(final TermsEnum reuse) throws IOException { - return new SortingTermsEnum(in.iterator(reuse), inLiveDocs, old2new, indexOptions); + return new SortingTermsEnum(in.iterator(reuse), inLiveDocs, docMap, indexOptions); } } private static class SortingTermsEnum extends FilterTermsEnum { - private final int[] old2new; + private final Sorter.DocMap docMap; private final Bits inLiveDocs; private final IndexOptions indexOptions; - public SortingTermsEnum(final TermsEnum in, final Bits inLiveDocs, final int[] old2new, IndexOptions indexOptions) { + public SortingTermsEnum(final TermsEnum in, final Bits inLiveDocs, Sorter.DocMap docMap, IndexOptions indexOptions) { super(in); - this.old2new = old2new; + this.docMap = docMap; this.inLiveDocs = inLiveDocs; this.indexOptions = indexOptions; } @@ -134,7 +133,7 @@ public class SortingAtomicReader extends FilterAtomicReader { reuse = ((SortingDocsEnum) reuse).getWrapped(); } boolean withFreqs = indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS) >=0 && (flags & DocsEnum.FLAG_FREQS) != 0; - return new SortingDocsEnum(in.docs(liveDocs, reuse, flags), withFreqs, old2new); + return new SortingDocsEnum(in.docs(liveDocs, reuse, flags), withFreqs, docMap); } @Override @@ -158,7 +157,7 @@ public class SortingAtomicReader extends FilterAtomicReader { // ask for everything. if that assumption changes in the future, we can // factor in whether 'flags' says offsets are not required. boolean storeOffsets = indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) >= 0; - return new SortingDocsAndPositionsEnum(positions, old2new, storeOffsets); + return new SortingDocsAndPositionsEnum(positions, docMap, storeOffsets); } } @@ -167,48 +166,48 @@ public class SortingAtomicReader extends FilterAtomicReader { private static class SortingBinaryDocValues extends BinaryDocValues { private final BinaryDocValues in; - private final int[] new2old; + private final Sorter.DocMap docMap; - SortingBinaryDocValues(BinaryDocValues in, int[] new2old) { + SortingBinaryDocValues(BinaryDocValues in, Sorter.DocMap docMap) { this.in = in; - this.new2old = new2old; + this.docMap = docMap; } @Override public void get(int docID, BytesRef result) { - in.get(new2old[docID], result); + in.get(docMap.newToOld(docID), result); } } private static class SortingNumericDocValues extends NumericDocValues { private final NumericDocValues in; - private final int[] new2old; + private final Sorter.DocMap docMap; - public SortingNumericDocValues(final NumericDocValues in, final int[] new2old) { + public SortingNumericDocValues(final NumericDocValues in, Sorter.DocMap docMap) { this.in = in; - this.new2old = new2old; + this.docMap = docMap; } @Override public long get(int docID) { - return in.get(new2old[docID]); + return in.get(docMap.newToOld(docID)); } } private static class SortingSortedDocValues extends SortedDocValues { private final SortedDocValues in; - private final int[] new2old; + private final Sorter.DocMap docMap; - SortingSortedDocValues(SortedDocValues in, int[] new2old) { + SortingSortedDocValues(SortedDocValues in, Sorter.DocMap docMap) { this.in = in; - this.new2old = new2old; + this.docMap = docMap; } @Override public int getOrd(int docID) { - return in.getOrd(new2old[docID]); + return in.getOrd(docMap.newToOld(docID)); } @Override @@ -223,7 +222,7 @@ public class SortingAtomicReader extends FilterAtomicReader { @Override public void get(int docID, BytesRef result) { - in.get(new2old[docID], result); + in.get(docMap.newToOld(docID), result); } @Override @@ -235,11 +234,11 @@ public class SortingAtomicReader extends FilterAtomicReader { private static class SortingSortedSetDocValues extends SortedSetDocValues { private final SortedSetDocValues in; - private final int[] new2old; + private final Sorter.DocMap docMap; - SortingSortedSetDocValues(SortedSetDocValues in, int[] new2old) { + SortingSortedSetDocValues(SortedSetDocValues in, Sorter.DocMap docMap) { this.in = in; - this.new2old = new2old; + this.docMap = docMap; } @Override @@ -249,7 +248,7 @@ public class SortingAtomicReader extends FilterAtomicReader { @Override public void setDocument(int docID) { - in.setDocument(new2old[docID]); + in.setDocument(docMap.newToOld(docID)); } @Override @@ -315,7 +314,7 @@ public class SortingAtomicReader extends FilterAtomicReader { private final int upto; private final boolean withFreqs; - public SortingDocsEnum(final DocsEnum in, boolean withFreqs, final int[] old2new) throws IOException { + public SortingDocsEnum(final DocsEnum in, boolean withFreqs, final Sorter.DocMap docMap) throws IOException { super(in); this.withFreqs = withFreqs; int i = 0; @@ -327,7 +326,7 @@ public class SortingAtomicReader extends FilterAtomicReader { docs = ArrayUtil.grow(docs, docs.length + 1); freqs = ArrayUtil.grow(freqs, freqs.length + 1); } - docs[i] = old2new[doc]; + docs[i] = docMap.oldToNew(doc); freqs[i] = in.freq(); ++i; } @@ -339,7 +338,7 @@ public class SortingAtomicReader extends FilterAtomicReader { if (i >= docs.length) { docs = ArrayUtil.grow(docs, docs.length + 1); } - docs[i++] = old2new[doc]; + docs[i++] = docMap.oldToNew(doc); } Arrays.sort(docs, 0, i); } @@ -436,7 +435,7 @@ public class SortingAtomicReader extends FilterAtomicReader { private final BytesRef payload = new BytesRef(32); private int currFreq; - public SortingDocsAndPositionsEnum(final DocsAndPositionsEnum in, final int[] old2new, boolean storeOffsets) throws IOException { + public SortingDocsAndPositionsEnum(final DocsAndPositionsEnum in, Sorter.DocMap docMap, boolean storeOffsets) throws IOException { super(in); this.storeOffsets = storeOffsets; final RAMFile file = new RAMFile(); @@ -454,7 +453,7 @@ public class SortingAtomicReader extends FilterAtomicReader { System.arraycopy(offsets, 0, tmp, 0, offsets.length); offsets = tmp; } - docs[i] = old2new[doc]; + docs[i] = docMap.oldToNew(doc); offsets[i] = out.getFilePointer(); addPositions(in, out); i++; @@ -551,38 +550,29 @@ public class SortingAtomicReader extends FilterAtomicReader { } } - private final int[] old2new, new2old; - private final FixedBitSet mappedLiveDocs; + /** Return a sorted view of reader according to the order + * defined by sorter. If the reader is already sorted, this + * method might return the reader as-is. */ + public static AtomicReader sort(AtomicReader reader, Sorter sorter) throws IOException { + final Sorter.DocMap docMap = sorter.sort(reader); + if (docMap == null) { + // the reader is already sorter + return reader; + } + assert Sorter.isConsistent(docMap, reader.maxDoc()); + return new SortingAtomicReader(reader, docMap); + } - public SortingAtomicReader(final AtomicReader in, final Sorter sorter) throws IOException { + private final Sorter.DocMap docMap; + + private SortingAtomicReader(final AtomicReader in, final Sorter.DocMap docMap) { super(in); - old2new = sorter.oldToNew(in); - if (old2new.length != in.maxDoc()) { - throw new IllegalArgumentException("sorter should provide mapping for every document in the index, including deleted ones"); - } - new2old = new int[old2new.length]; - for (int i = 0; i < new2old.length; i++) { - new2old[old2new[i]] = i; - } - - if (!in.hasDeletions()) { - mappedLiveDocs = null; - } else { - mappedLiveDocs = new FixedBitSet(in.maxDoc()); - mappedLiveDocs.set(0, in.maxDoc()); - Bits liveDocs = in.getLiveDocs(); - int len = liveDocs.length(); - for (int i = 0; i < len; i++) { - if (!liveDocs.get(i)) { - mappedLiveDocs.clear(old2new[i]); - } - } - } + this.docMap = docMap; } @Override public void document(final int docID, final StoredFieldVisitor visitor) throws IOException { - in.document(new2old[docID], visitor); + in.document(docMap.newToOld(docID), visitor); } @Override @@ -591,7 +581,7 @@ public class SortingAtomicReader extends FilterAtomicReader { if (fields == null) { return null; } else { - return new SortingFields(fields, in.getLiveDocs(), in.getFieldInfos(), old2new); + return new SortingFields(fields, in.getLiveDocs(), in.getFieldInfos(), docMap); } } @@ -601,14 +591,29 @@ public class SortingAtomicReader extends FilterAtomicReader { if (oldDocValues == null) { return null; } else { - return new SortingBinaryDocValues(oldDocValues, new2old); + return new SortingBinaryDocValues(oldDocValues, docMap); } } @Override public Bits getLiveDocs() { - ensureOpen(); - return mappedLiveDocs; + final Bits inLiveDocs = in.getLiveDocs(); + if (inLiveDocs == null) { + return null; + } + return new Bits() { + + @Override + public boolean get(int index) { + return inLiveDocs.get(docMap.newToOld(index)); + } + + @Override + public int length() { + return inLiveDocs.length(); + } + + }; } @Override @@ -617,7 +622,7 @@ public class SortingAtomicReader extends FilterAtomicReader { if (norm == null) { return null; } else { - return new SortingNumericDocValues(norm, new2old); + return new SortingNumericDocValues(norm, docMap); } } @@ -625,7 +630,7 @@ public class SortingAtomicReader extends FilterAtomicReader { public NumericDocValues getNumericDocValues(String field) throws IOException { final NumericDocValues oldDocValues = in.getNumericDocValues(field); if (oldDocValues == null) return null; - return new SortingNumericDocValues(oldDocValues, new2old); + return new SortingNumericDocValues(oldDocValues, docMap); } @Override @@ -634,7 +639,7 @@ public class SortingAtomicReader extends FilterAtomicReader { if (sortedDV == null) { return null; } else { - return new SortingSortedDocValues(sortedDV, new2old); + return new SortingSortedDocValues(sortedDV, docMap); } } @@ -644,13 +649,13 @@ public class SortingAtomicReader extends FilterAtomicReader { if (sortedSetDV == null) { return null; } else { - return new SortingSortedSetDocValues(sortedSetDV, new2old); + return new SortingSortedSetDocValues(sortedSetDV, docMap); } } @Override public Fields getTermVectors(final int docID) throws IOException { - return in.getTermVectors(new2old[docID]); + return in.getTermVectors(docMap.newToOld(docID)); } } diff --git a/lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java b/lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java index 819cd957892..e2eba120e9a 100644 --- a/lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java +++ b/lucene/misc/src/test/org/apache/lucene/index/sorter/IndexSortingTest.java @@ -61,7 +61,7 @@ public class IndexSortingTest extends SorterTestBase { Directory target = newDirectory(); IndexWriter writer = new IndexWriter(target, newIndexWriterConfig(TEST_VERSION_CURRENT, null)); - reader = new SortingAtomicReader(reader, sorter); + reader = SortingAtomicReader.sort(reader, sorter); writer.addIndexes(reader); writer.close(); reader.close(); diff --git a/lucene/misc/src/test/org/apache/lucene/index/sorter/SortingAtomicReaderTest.java b/lucene/misc/src/test/org/apache/lucene/index/sorter/SortingAtomicReaderTest.java index adb430ad7b3..6fb40184106 100644 --- a/lucene/misc/src/test/org/apache/lucene/index/sorter/SortingAtomicReaderTest.java +++ b/lucene/misc/src/test/org/apache/lucene/index/sorter/SortingAtomicReaderTest.java @@ -19,7 +19,6 @@ package org.apache.lucene.index.sorter; import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import org.apache.lucene.index.AtomicReader; import org.apache.lucene.util.Bits; @@ -33,28 +32,34 @@ public class SortingAtomicReaderTest extends SorterTestBase { // build the mapping from the reader, since we deleted documents, some of // them might have disappeared from the index (e.g. if an entire segment is // dropped b/c all its docs are deleted) - Integer[] values = new Integer[reader.maxDoc()]; - int[] docs = new int[reader.maxDoc()]; + final int[] values = new int[reader.maxDoc()]; for (int i = 0; i < reader.maxDoc(); i++) { - docs[i] = i; values[i] = Integer.valueOf(reader.document(i).get(ID_FIELD)); } + final Sorter.DocComparator comparator = new Sorter.DocComparator() { + @Override + public int compare(int docID1, int docID2) { + final int v1 = values[docID1]; + final int v2 = values[docID2]; + return v1 < v2 ? -1 : v1 == v2 ? 0 : 1; + } + }; - final int[] oldToNew = Sorter.compute(docs, Collections.unmodifiableList(Arrays.asList(values))); + final Sorter.DocMap docMap = Sorter.sort(reader.maxDoc(), comparator); // Sorter.compute also sorts the values sortedValues = new Integer[reader.maxDoc()]; for (int i = 0; i < reader.maxDoc(); ++i) { - sortedValues[oldToNew[i]] = values[i]; + sortedValues[docMap.oldToNew(i)] = values[i]; } if (VERBOSE) { - System.out.println("oldToNew: " + Arrays.toString(oldToNew)); + System.out.println("docMap: " + docMap); System.out.println("sortedValues: " + Arrays.toString(sortedValues)); } - reader = new SortingAtomicReader(reader, new Sorter() { + reader = SortingAtomicReader.sort(reader, new Sorter() { @Override - public int[] oldToNew(AtomicReader reader) throws IOException { - return oldToNew; + public Sorter.DocMap sort(AtomicReader reader) throws IOException { + return docMap; } });