Index: lucene/src/test/org/apache/lucene/search/TestSort.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestSort.java (revision 1183276) +++ lucene/src/test/org/apache/lucene/search/TestSort.java (working copy) @@ -125,6 +125,8 @@ dirs.add(indexStore); RandomIndexWriter writer = new RandomIndexWriter(random, indexStore, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMergePolicy(newLogMergePolicy())); + final ValueType stringDVType = random.nextBoolean() ? ValueType.BYTES_VAR_SORTED : ValueType.BYTES_FIXED_SORTED; + FieldType ft1 = new FieldType(); ft1.setStored(true); FieldType ft2 = new FieldType(); @@ -138,7 +140,7 @@ Field f = new StringField ("int", data[i][2]); if (supportsDocValues) { f = IndexDocValuesField.build(f, ValueType.VAR_INTS); - }; + } doc.add(f); } if (data[i][3] != null) { @@ -148,7 +150,13 @@ } doc.add(f); } - if (data[i][4] != null) doc.add (new StringField ("string", data[i][4])); + if (data[i][4] != null) { + Field f = new StringField ("string", data[i][4]); + if (supportsDocValues) { + f = IndexDocValuesField.build(f, stringDVType); + } + doc.add(f); + } if (data[i][5] != null) doc.add (new StringField ("custom", data[i][5])); if (data[i][6] != null) doc.add (new StringField ("i18n", data[i][6])); if (data[i][7] != null) doc.add (new StringField ("long", data[i][7])); @@ -191,23 +199,55 @@ setMaxBufferedDocs(4). setMergePolicy(newLogMergePolicy(97)) ); - FieldType customType = new FieldType(); - customType.setStored(true); + FieldType onlyStored = new FieldType(); + onlyStored.setStored(true); + final int fixedLen = getRandomNumber(2, 8); + final int fixedLen2 = getRandomNumber(1, 4); for (int i=0; i= 0)) { // ensure first field is in order fail = true; System.out.println("fail:" + v[j] + " < " + last); + buff.append(" WRONG tracer\n"); } if (cmp == 0) { // ensure second field is in reverse order cmp = v2[j].stringValue().compareTo(lastSub); if (cmp > 0) { fail = true; System.out.println("rev field fail:" + v2[j] + " > " + lastSub); + buff.append(" WRONG tracer2\n"); } else if(cmp == 0) { // ensure docid is in order if (result[x].doc < lastDocId) { fail = true; System.out.println("doc fail:" + result[x].doc + " > " + lastDocId); + buff.append(" WRONG docID\n"); } } } @@ -430,11 +503,10 @@ last = v[j].stringValue(); lastSub = v2[j].stringValue(); lastDocId = result[x].doc; - buff.append(v[j] + "(" + v2[j] + ")(" + result[x].doc+") "); } } - if(fail) { - System.out.println("topn field1(field2)(docID):" + buff); + if (fail) { + System.out.println("topn field1(field2)(docID):\n" + buff); } assertFalse("Found sort results out of order", fail); searcher.close(); @@ -531,6 +603,16 @@ sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT)), new SortField ("string", SortField.Type.STRING) ); assertMatches (empty, queryX, sort, ""); + + sort.setSort (useDocValues(new SortField ("string", SortField.Type.STRING, true)), SortField.FIELD_DOC ); + assertMatches (empty, queryX, sort, ""); + + sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT)), + useDocValues(new SortField ("string", SortField.Type.STRING)) ); + assertMatches (empty, queryX, sort, ""); + + sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT)), useDocValues(new SortField ("string", SortField.Type.STRING)) ); + assertMatches (empty, queryX, sort, ""); } static class MyFieldComparator extends FieldComparator { @@ -624,11 +706,18 @@ sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT, true)) ); assertMatches (full, queryX, sort, "AECIG"); assertMatches (full, queryY, sort, "BFJHD"); + + sort.setSort (useDocValues(new SortField ("string", SortField.Type.STRING, true)) ); + assertMatches (full, queryX, sort, "CEGIA"); + assertMatches (full, queryY, sort, "BFHJD"); } } // test sorting when the sort field is empty (undefined) for some of the documents public void testEmptyFieldSort() throws Exception { + + // NOTE: do not test DocValues fields here, since you + // can't sort when some documents don't have the field sort.setSort (new SortField ("string", SortField.Type.STRING) ); assertMatches (full, queryF, sort, "ZJI"); @@ -644,14 +733,6 @@ sort.setSort (new SortField ("float", SortField.Type.FLOAT) ); assertMatches (full, queryF, sort, "ZJI"); - if (supportsDocValues) { - sort.setSort (useDocValues(new SortField ("int", SortField.Type.INT)) ); - assertMatches (full, queryF, sort, "IZJ"); - - sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT)) ); - assertMatches (full, queryF, sort, "ZJI"); - } - // using a nonexisting field as first sort key shouldn't make a difference: sort.setSort (new SortField ("nosuchfield", SortField.Type.STRING), new SortField ("float", SortField.Type.FLOAT) ); @@ -661,7 +742,6 @@ assertMatches (full, queryF, sort, "IJZ"); // When a field is null for both documents, the next SortField should be used. - // Works for sort.setSort (new SortField ("int", SortField.Type.INT), new SortField ("string", SortField.Type.STRING), new SortField ("float", SortField.Type.FLOAT) ); @@ -670,7 +750,7 @@ // Reverse the last criterium to make sure the test didn't pass by chance sort.setSort (new SortField ("int", SortField.Type.INT), new SortField ("string", SortField.Type.STRING), - new SortField ("float", SortField.Type.FLOAT, true) ); + new SortField ("float", SortField.Type.FLOAT, true) ); assertMatches (full, queryG, sort, "ZYXW"); // Do the same for a ParallelMultiSearcher @@ -678,13 +758,13 @@ IndexSearcher parallelSearcher=new IndexSearcher (full.getIndexReader(), exec); sort.setSort (new SortField ("int", SortField.Type.INT), - new SortField ("string", SortField.Type.STRING), - new SortField ("float", SortField.Type.FLOAT) ); + new SortField ("string", SortField.Type.STRING), + new SortField ("float", SortField.Type.FLOAT) ); assertMatches (parallelSearcher, queryG, sort, "ZWXY"); sort.setSort (new SortField ("int", SortField.Type.INT), - new SortField ("string", SortField.Type.STRING), - new SortField ("float", SortField.Type.FLOAT, true) ); + new SortField ("string", SortField.Type.STRING), + new SortField ("float", SortField.Type.FLOAT, true) ); assertMatches (parallelSearcher, queryG, sort, "ZYXW"); parallelSearcher.close(); exec.shutdown(); @@ -701,6 +781,20 @@ sort.setSort (new SortField ("float", SortField.Type.FLOAT), new SortField ("string", SortField.Type.STRING) ); assertMatches (full, queryX, sort, "GICEA"); + + if (supportsDocValues) { + sort.setSort (useDocValues(new SortField ("int", SortField.Type.INT)), + useDocValues(new SortField ("float", SortField.Type.FLOAT))); + assertMatches (full, queryX, sort, "IGEAC"); + + sort.setSort (useDocValues(new SortField ("int", SortField.Type.INT, true)), + useDocValues(new SortField (null, SortField.Type.DOC, true))); + assertMatches (full, queryX, sort, "CEAGI"); + + sort.setSort (useDocValues(new SortField ("float", SortField.Type.FLOAT)), + useDocValues(new SortField ("string", SortField.Type.STRING))); + assertMatches (full, queryX, sort, "GICEA"); + } } // test a variety of sorts using a parallel multisearcher @@ -1045,6 +1139,21 @@ sort.setSort(useDocValues(new SortField ("int", SortField.Type.INT, true))); assertMatches(multi, queryF, sort, "JZI"); + + sort.setSort(useDocValues(new SortField("string", SortField.Type.STRING))); + assertMatches(multi, queryA, sort, "DJAIHGFEBC"); + + sort.setSort(useDocValues(new SortField("string", SortField.Type.STRING, true))); + assertMatches(multi, queryA, sort, "CBEFGHIAJD"); + + sort.setSort(useDocValues(new SortField("float", SortField.Type.FLOAT)),useDocValues(new SortField("string", SortField.Type.STRING))); + assertMatches(multi, queryA, sort, "GDHJICEFAB"); + + sort.setSort(useDocValues(new SortField ("string", SortField.Type.STRING))); + assertMatches(multi, queryF, sort, "ZJI"); + + sort.setSort(useDocValues(new SortField ("string", SortField.Type.STRING, true))); + assertMatches(multi, queryF, sort, "IJZ"); } // up to this point, all of the searches should have "sane" Index: lucene/src/java/org/apache/lucene/search/FieldComparator.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldComparator.java (revision 1183276) +++ lucene/src/java/org/apache/lucene/search/FieldComparator.java (working copy) @@ -20,6 +20,7 @@ import org.apache.lucene.index.IndexReader.AtomicReaderContext; import org.apache.lucene.index.values.IndexDocValues; import org.apache.lucene.index.values.IndexDocValues.Source; +import org.apache.lucene.index.values.IndexDocValues.SortedSource; import org.apache.lucene.search.FieldCache.DocTerms; import org.apache.lucene.search.FieldCache.DocTermsIndex; import org.apache.lucene.search.cache.*; @@ -29,6 +30,7 @@ import org.apache.lucene.util.packed.PackedInts; import java.io.IOException; +import java.util.Comparator; /** * Expert: a FieldComparator compares hits so as to determine their @@ -358,6 +360,9 @@ @Override public int compareBottom(int doc) { + if (currentReaderValues == null) { + throw new IllegalStateException("some hits are missing docValues for field \"" + field + "\""); + } final double v2 = currentReaderValues.getFloat(doc); if (bottom > v2) { return 1; @@ -370,6 +375,9 @@ @Override public void copy(int slot, int doc) { + if (currentReaderValues == null) { + throw new IllegalStateException("some hits are missing docValues for field \"" + field + "\""); + } values[slot] = currentReaderValues.getFloat(doc); } @@ -378,6 +386,8 @@ final IndexDocValues docValues = context.reader.docValues(field); if (docValues != null) { currentReaderValues = docValues.getSource(); + } else { + currentReaderValues = null; } return this; } @@ -630,6 +640,9 @@ @Override public int compareBottom(int doc) { + if (currentReaderValues == null) { + throw new IllegalStateException("some hits are missing docValues for field \"" + field + "\""); + } // TODO: there are sneaky non-branch ways to compute // -1/+1/0 sign final long v2 = currentReaderValues.getInt(doc); @@ -644,6 +657,9 @@ @Override public void copy(int slot, int doc) { + if (currentReaderValues == null) { + throw new IllegalStateException("some hits are missing docValues for field \"" + field + "\""); + } values[slot] = currentReaderValues.getInt(doc); } @@ -652,6 +668,8 @@ IndexDocValues docValues = context.reader.docValues(field); if (docValues != null) { currentReaderValues = docValues.getSource(); + } else { + currentReaderValues = null; } return this; } @@ -891,7 +909,7 @@ /** @lucene.internal */ final BytesRef tempBR = new BytesRef(); - public TermOrdValComparator(int numHits, String field, int sortPos, boolean reversed) { + public TermOrdValComparator(int numHits, String field) { ords = new int[numHits]; values = new BytesRef[numHits]; readerGen = new int[numHits]; @@ -1282,6 +1300,406 @@ } } + /** Sorts by field's natural Term sort order, using + * ordinals; this is just like {@link + * TermOrdValuesComparator} except it uses DocValues to + * retrieve the sort ords saved during indexing. */ + public static final class TermOrdValDocValuesComparator extends FieldComparator { + /** @lucene.internal */ + final int[] ords; + /** @lucene.internal */ + final BytesRef[] values; + /** @lucene.internal */ + final int[] readerGen; + + /** @lucene.internal */ + int currentReaderGen = -1; + private SortedSource termsIndex; + private Comparator comp; + private final String field; + + /** @lucene.internal */ + int bottomSlot = -1; + /** @lucene.internal */ + int bottomOrd; + /** @lucene.internal */ + boolean bottomSameReader; + /** @lucene.internal */ + BytesRef bottomValue; + /** @lucene.internal */ + final BytesRef tempBR = new BytesRef(); + + public TermOrdValDocValuesComparator(int numHits, String field) { + ords = new int[numHits]; + values = new BytesRef[numHits]; + readerGen = new int[numHits]; + this.field = field; + } + + @Override + public int compare(int slot1, int slot2) { + if (readerGen[slot1] == readerGen[slot2]) { + return ords[slot1] - ords[slot2]; + } + + final BytesRef val1 = values[slot1]; + final BytesRef val2 = values[slot2]; + if (val1 == null) { + if (val2 == null) { + return 0; + } + return -1; + } else if (val2 == null) { + return 1; + } + return comp.compare(val1, val2); + } + + @Override + public int compareBottom(int doc) { + throw new UnsupportedOperationException(); + } + + @Override + public void copy(int slot, int doc) { + throw new UnsupportedOperationException(); + } + + // TODO: would be nice to share these specialized impls + // w/ TermOrdValComparator + + /** Base class for specialized (per bit width of the + * ords) per-segment comparator. NOTE: this is messy; + * we do this only because hotspot can't reliably inline + * the underlying array access when looking up doc->ord + * @lucene.internal + */ + abstract class PerSegmentComparator extends FieldComparator { + + @Override + public FieldComparator setNextReader(AtomicReaderContext context) throws IOException { + return TermOrdValDocValuesComparator.this.setNextReader(context); + } + + @Override + public int compare(int slot1, int slot2) { + return TermOrdValDocValuesComparator.this.compare(slot1, slot2); + } + + @Override + public void setBottom(final int bottom) { + TermOrdValDocValuesComparator.this.setBottom(bottom); + } + + @Override + public BytesRef value(int slot) { + return TermOrdValDocValuesComparator.this.value(slot); + } + + @Override + public int compareValues(BytesRef val1, BytesRef val2) { + assert val1 != null; + assert val2 != null; + return comp.compare(val1, val2); + } + } + + // Used per-segment when bit width of doc->ord is 8: + private final class ByteOrdComparator extends PerSegmentComparator { + private final byte[] readerOrds; + private final SortedSource termsIndex; + private final int docBase; + + public ByteOrdComparator(byte[] readerOrds, SortedSource termsIndex, int docBase) { + this.readerOrds = readerOrds; + this.termsIndex = termsIndex; + this.docBase = docBase; + } + + @Override + public int compareBottom(int doc) { + assert bottomSlot != -1; + if (bottomSameReader) { + // ord is precisely comparable, even in the equal case + return bottomOrd - (readerOrds[doc]&0xFF); + } else { + // ord is only approx comparable: if they are not + // equal, we can use that; if they are equal, we + // must fallback to compare by value + final int order = readerOrds[doc]&0xFF; + final int cmp = bottomOrd - order; + if (cmp != 0) { + return cmp; + } + + termsIndex.getByOrd(order, tempBR); + return comp.compare(bottomValue, tempBR); + } + } + + @Override + public void copy(int slot, int doc) { + final int ord = readerOrds[doc]&0xFF; + ords[slot] = ord; + if (values[slot] == null) { + values[slot] = new BytesRef(); + } + termsIndex.getByOrd(ord, values[slot]); + readerGen[slot] = currentReaderGen; + } + } + + // Used per-segment when bit width of doc->ord is 16: + private final class ShortOrdComparator extends PerSegmentComparator { + private final short[] readerOrds; + private final SortedSource termsIndex; + private final int docBase; + + public ShortOrdComparator(short[] readerOrds, SortedSource termsIndex, int docBase) { + this.readerOrds = readerOrds; + this.termsIndex = termsIndex; + this.docBase = docBase; + } + + @Override + public int compareBottom(int doc) { + assert bottomSlot != -1; + if (bottomSameReader) { + // ord is precisely comparable, even in the equal case + return bottomOrd - (readerOrds[doc]&0xFFFF); + } else { + // ord is only approx comparable: if they are not + // equal, we can use that; if they are equal, we + // must fallback to compare by value + final int order = readerOrds[doc]&0xFFFF; + final int cmp = bottomOrd - order; + if (cmp != 0) { + return cmp; + } + + termsIndex.getByOrd(order, tempBR); + return comp.compare(bottomValue, tempBR); + } + } + + @Override + public void copy(int slot, int doc) { + final int ord = readerOrds[doc]&0xFFFF; + ords[slot] = ord; + if (values[slot] == null) { + values[slot] = new BytesRef(); + } + termsIndex.getByOrd(ord, values[slot]); + readerGen[slot] = currentReaderGen; + } + } + + // Used per-segment when bit width of doc->ord is 32: + private final class IntOrdComparator extends PerSegmentComparator { + private final int[] readerOrds; + private final SortedSource termsIndex; + private final int docBase; + + public IntOrdComparator(int[] readerOrds, SortedSource termsIndex, int docBase) { + this.readerOrds = readerOrds; + this.termsIndex = termsIndex; + this.docBase = docBase; + } + + @Override + public int compareBottom(int doc) { + assert bottomSlot != -1; + if (bottomSameReader) { + // ord is precisely comparable, even in the equal case + return bottomOrd - readerOrds[doc]; + } else { + // ord is only approx comparable: if they are not + // equal, we can use that; if they are equal, we + // must fallback to compare by value + final int order = readerOrds[doc]; + final int cmp = bottomOrd - order; + if (cmp != 0) { + return cmp; + } + termsIndex.getByOrd(order, tempBR); + return comp.compare(bottomValue, tempBR); + } + } + + @Override + public void copy(int slot, int doc) { + final int ord = readerOrds[doc]; + ords[slot] = ord; + if (values[slot] == null) { + values[slot] = new BytesRef(); + } + termsIndex.getByOrd(ord, values[slot]); + readerGen[slot] = currentReaderGen; + } + } + + // Used per-segment when bit width is not a native array + // size (8, 16, 32): + private final class AnyOrdComparator extends PerSegmentComparator { + private final PackedInts.Reader readerOrds; + private final int docBase; + + public AnyOrdComparator(PackedInts.Reader readerOrds, int docBase) { + this.readerOrds = readerOrds; + this.docBase = docBase; + } + + @Override + public int compareBottom(int doc) { + assert bottomSlot != -1; + if (bottomSameReader) { + // ord is precisely comparable, even in the equal case + return bottomOrd - (int) readerOrds.get(doc); + } else { + // ord is only approx comparable: if they are not + // equal, we can use that; if they are equal, we + // must fallback to compare by value + final int order = (int) readerOrds.get(doc); + final int cmp = bottomOrd - order; + if (cmp != 0) { + return cmp; + } + termsIndex.getByOrd(order, tempBR); + return comp.compare(bottomValue, tempBR); + } + } + + @Override + public void copy(int slot, int doc) { + final int ord = (int) readerOrds.get(doc); + ords[slot] = ord; + if (values[slot] == null) { + values[slot] = new BytesRef(); + } + termsIndex.getByOrd(ord, values[slot]); + readerGen[slot] = currentReaderGen; + } + } + + private final class NoMatchComparator extends PerSegmentComparator { + @Override + public int compareBottom(int doc) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + + @Override + public void copy(int slot, int doc) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + + @Override + public int compare(int slot1, int slot2) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + + @Override + public void setBottom(final int bottom) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + + @Override + public BytesRef value(int slot) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + + @Override + public int compareValues(BytesRef val1, BytesRef val2) { + throw new IllegalStateException("some hits are missing sorted docValues field \"" + field + "\""); + } + } + + @Override + public FieldComparator setNextReader(AtomicReaderContext context) throws IOException { + final int docBase = context.docBase; + + final IndexDocValues dv = context.reader.docValues(field); + if (dv == null) { + termsIndex = null; + comp = null; + currentReaderGen++; + return new NoMatchComparator(); + } + + termsIndex = dv.getSource().asSortedSource(); + if (termsIndex == null) { + currentReaderGen++; + comp = null; + return new NoMatchComparator(); + } + + comp = termsIndex.getComparator(); + + FieldComparator perSegComp = null; + final PackedInts.Reader docToOrd = termsIndex.getDocToOrd(); + if (docToOrd.hasArray()) { + final Object arr = docToOrd.getArray(); + assert arr != null; + if (arr instanceof byte[]) { + // 8 bit packed + perSegComp = new ByteOrdComparator((byte[]) arr, termsIndex, docBase); + } else if (arr instanceof short[]) { + // 16 bit packed + perSegComp = new ShortOrdComparator((short[]) arr, termsIndex, docBase); + } else if (arr instanceof int[]) { + // 32 bit packed + perSegComp = new IntOrdComparator((int[]) arr, termsIndex, docBase); + } + } + + if (perSegComp == null) { + perSegComp = new AnyOrdComparator(docToOrd, docBase); + } + + currentReaderGen++; + if (bottomSlot != -1) { + perSegComp.setBottom(bottomSlot); + } + + return perSegComp; + } + + @Override + public void setBottom(final int bottom) { + bottomSlot = bottom; + + bottomValue = values[bottomSlot]; + if (currentReaderGen == readerGen[bottomSlot]) { + bottomOrd = ords[bottomSlot]; + bottomSameReader = true; + } else { + if (bottomValue == null) { + // 0 ord is null for all segments + assert ords[bottomSlot] == 0; + bottomOrd = 0; + bottomSameReader = true; + readerGen[bottomSlot] = currentReaderGen; + } else { + final int index = termsIndex.getByValue(bottomValue, tempBR); + if (index < 0) { + bottomOrd = -index - 2; + bottomSameReader = false; + } else { + bottomOrd = index; + // exact value match + bottomSameReader = true; + readerGen[bottomSlot] = currentReaderGen; + ords[bottomSlot] = bottomOrd; + } + } + } + } + + @Override + public BytesRef value(int slot) { + return values[slot]; + } + } + /** Sorts by field's natural Term sort order. All * comparisons are done using BytesRef.compareTo, which is * slow for medium to large result sets but possibly Index: lucene/src/java/org/apache/lucene/search/SortField.java =================================================================== --- lucene/src/java/org/apache/lucene/search/SortField.java (revision 1183276) +++ lucene/src/java/org/apache/lucene/search/SortField.java (working copy) @@ -475,7 +475,11 @@ return comparatorSource.newComparator(field, numHits, sortPos, reverse); case STRING: - return new FieldComparator.TermOrdValComparator(numHits, field, sortPos, reverse); + if (useIndexValues) { + return new FieldComparator.TermOrdValDocValuesComparator(numHits, field); + } else { + return new FieldComparator.TermOrdValComparator(numHits, field); + } case STRING_VAL: return new FieldComparator.TermValComparator(numHits, field); Index: lucene/src/java/org/apache/lucene/index/values/IndexDocValues.java =================================================================== --- lucene/src/java/org/apache/lucene/index/values/IndexDocValues.java (revision 1183276) +++ lucene/src/java/org/apache/lucene/index/values/IndexDocValues.java (working copy) @@ -27,6 +27,7 @@ import org.apache.lucene.index.codecs.Codec; import org.apache.lucene.index.codecs.CodecProvider; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.packed.PackedInts; /** * {@link IndexDocValues} provides a dense per-document typed storage for fast @@ -261,6 +262,20 @@ public abstract BytesRef getByOrd(int ord, BytesRef bytesRef); /** + * Returns the PackedInts.Reader impl that maps document to ord. + */ + public PackedInts.Reader getDocToOrd() { + return null; + } + + /** + * Returns the comparator used to order the BytesRefs. + */ + public Comparator getComparator() { + return comparator; + } + + /** * Performs a lookup by value. * * @param value Index: lucene/src/java/org/apache/lucene/index/values/Bytes.java =================================================================== --- lucene/src/java/org/apache/lucene/index/values/Bytes.java (revision 1183276) +++ lucene/src/java/org/apache/lucene/index/values/Bytes.java (working copy) @@ -32,17 +32,17 @@ import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.apache.lucene.util.ArrayUtil; +import org.apache.lucene.util.ByteBlockPool.Allocator; +import org.apache.lucene.util.ByteBlockPool.DirectTrackingAllocator; import org.apache.lucene.util.ByteBlockPool; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.BytesRefHash.TrackingDirectBytesStartArray; import org.apache.lucene.util.BytesRefHash; import org.apache.lucene.util.CodecUtil; import org.apache.lucene.util.Counter; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.PagedBytes; import org.apache.lucene.util.RamUsageEstimator; -import org.apache.lucene.util.ByteBlockPool.Allocator; -import org.apache.lucene.util.ByteBlockPool.DirectTrackingAllocator; -import org.apache.lucene.util.BytesRefHash.TrackingDirectBytesStartArray; import org.apache.lucene.util.packed.PackedInts; /** @@ -584,7 +584,11 @@ this.idxIn = idxIn; ordToOffsetIndex = hasOffsets ? PackedInts.getReader(idxIn) : null; docToOrdIndex = PackedInts.getReader(idxIn); + } + @Override + public PackedInts.Reader getDocToOrd() { + return docToOrdIndex; } @Override Index: lucene/src/java/org/apache/lucene/document/FieldType.java =================================================================== --- lucene/src/java/org/apache/lucene/document/FieldType.java (revision 1183276) +++ lucene/src/java/org/apache/lucene/document/FieldType.java (working copy) @@ -145,34 +145,34 @@ if (result.length() > 0) result.append(","); result.append("indexed"); + if (tokenized()) { + if (result.length() > 0) + result.append(","); + result.append("tokenized"); + } + if (storeTermVectors()) { + if (result.length() > 0) + result.append(","); + result.append("termVector"); + } + if (storeTermVectorOffsets()) { + if (result.length() > 0) + result.append(","); + result.append("termVectorOffsets"); + } + if (storeTermVectorPositions()) { + if (result.length() > 0) + result.append(","); + result.append("termVectorPosition"); + } + if (omitNorms()) { + result.append(",omitNorms"); + } + if (indexOptions != IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) { + result.append(",indexOptions="); + result.append(indexOptions); + } } - if (tokenized()) { - if (result.length() > 0) - result.append(","); - result.append("tokenized"); - } - if (storeTermVectors()) { - if (result.length() > 0) - result.append(","); - result.append("termVector"); - } - if (storeTermVectorOffsets()) { - if (result.length() > 0) - result.append(","); - result.append("termVectorOffsets"); - } - if (storeTermVectorPositions()) { - if (result.length() > 0) - result.append(","); - result.append("termVectorPosition"); - } - if (omitNorms()) { - result.append(",omitNorms"); - } - if (indexOptions != IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) { - result.append(",indexOptions="); - result.append(indexOptions); - } return result.toString(); }