Make ordinals start at 0.

Our ordinals currently start at 1, like FieldCache did in older Lucene versions.
However, Lucene 4.2 changed it in order to make ordinals start at 0, using -1
as the ordinal for the missing value. We should switch to the same numbering as
Lucene for consistency. This also allows to remove some abstraction on top of
Lucene doc values.

Close #5871
This commit is contained in:
Adrien Grand 2014-04-24 22:20:38 +02:00
parent aa4dc092da
commit fc32875ae9
25 changed files with 152 additions and 172 deletions

View File

@ -242,7 +242,7 @@ public final class BytesRefOrdValComparator extends NestedWrappableComparator<By
ords[slot] = missingOrd;
values[slot] = missingValue;
} else {
assert ord > 0;
assert ord >= 0;
ords[slot] = ord << 2;
if (values[slot] == null || values[slot] == missingValue) {
values[slot] = new BytesRef();
@ -261,11 +261,9 @@ public final class BytesRefOrdValComparator extends NestedWrappableComparator<By
// for assertions
private boolean consistentInsertedOrd(BytesValues.WithOrdinals termsIndex, long ord, BytesRef value) {
assert ord >= 0 : ord;
assert (ord == 0) == (value == null) : "ord=" + ord + ", value=" + value;
final long previousOrd = ord >>> 2;
final long previousOrd = ord >> 2;
final long nextOrd = previousOrd + 1;
final BytesRef previous = previousOrd == 0 ? null : termsIndex.getValueByOrd(previousOrd);
final BytesRef previous = previousOrd == Ordinals.MISSING_ORDINAL ? null : termsIndex.getValueByOrd(previousOrd);
if ((ord & 3) == 0) { // there was an existing ord with the inserted value
assert compareValues(previous, value) == 0;
} else {
@ -281,7 +279,6 @@ public final class BytesRefOrdValComparator extends NestedWrappableComparator<By
// find where to insert an ord in the current terms index
private long ordInCurrentReader(BytesValues.WithOrdinals termsIndex, BytesRef value) {
final long docOrd = binarySearch(termsIndex, value);
assert docOrd != -1; // would mean smaller than null
final long ord;
if (docOrd >= 0) {
// value exists in the current segment
@ -398,13 +395,13 @@ public final class BytesRefOrdValComparator extends NestedWrappableComparator<By
static long getRelevantOrd(Ordinals.Docs readerOrds, int docId, SortMode sortMode) {
int length = readerOrds.setDocument(docId);
long relevantVal = sortMode.startLong();
long result = 0;
long result = Ordinals.MISSING_ORDINAL;
assert sortMode == SortMode.MAX || sortMode == SortMode.MIN;
for (int i = 0; i < length; i++) {
result = relevantVal = sortMode.apply(readerOrds.nextOrd(), relevantVal);
}
assert result >= 0;
assert result <= readerOrds.getMaxOrd();
assert result >= Ordinals.MISSING_ORDINAL;
assert result < readerOrds.getMaxOrd();
return result;
// Enable this when the api can tell us that the ords per doc are ordered
/*if (reversed) {

View File

@ -56,7 +56,7 @@ public enum EmptyOrdinals implements Ordinals {
@Override
public long getOrd(int docId) {
return 0;
return Ordinals.MISSING_ORDINAL;
}
@Override
@ -71,7 +71,7 @@ public enum EmptyOrdinals implements Ordinals {
@Override
public long currentOrd() {
return 0;
return Ordinals.MISSING_ORDINAL;
}
}
}

View File

@ -64,9 +64,7 @@ public class InternalGlobalOrdinalsBuilder extends AbstractIndexComponent implem
// it makes sense to force COMPACT for them
final float acceptableOverheadRatio = settings.getAsFloat("acceptable_overhead_ratio", PackedInts.FAST);
final AppendingPackedLongBuffer globalOrdToFirstSegment = new AppendingPackedLongBuffer(PackedInts.COMPACT);
globalOrdToFirstSegment.add(0);
final MonotonicAppendingLongBuffer globalOrdToFirstSegmentDelta = new MonotonicAppendingLongBuffer(PackedInts.COMPACT);
globalOrdToFirstSegmentDelta.add(0);
FieldDataType fieldDataType = indexFieldData.getFieldDataType();
int defaultThreshold = settings.getAsInt(ORDINAL_MAPPING_THRESHOLD_INDEX_SETTING_KEY, ORDINAL_MAPPING_THRESHOLD_DEFAULT);
@ -79,13 +77,13 @@ public class InternalGlobalOrdinalsBuilder extends AbstractIndexComponent implem
final AtomicFieldData.WithOrdinals[] withOrdinals = new AtomicFieldData.WithOrdinals[indexReader.leaves().size()];
TermIterator termIterator = new TermIterator(indexFieldData, indexReader.leaves(), withOrdinals);
for (BytesRef term = termIterator.next(); term != null; term = termIterator.next()) {
currentGlobalOrdinal++;
globalOrdToFirstSegment.add(termIterator.firstReaderIndex());
long globalOrdinalDelta = currentGlobalOrdinal - termIterator.firstLocalOrdinal();
globalOrdToFirstSegmentDelta.add(globalOrdinalDelta);
for (TermIterator.LeafSource leafSource : termIterator.competitiveLeafs()) {
ordinalMappingBuilder.onOrdinal(leafSource.context.ord, leafSource.tenum.ord(), currentGlobalOrdinal);
}
currentGlobalOrdinal++;
}
// ram used for the globalOrd to segmentOrd and segmentOrd to firstReaderIndex lookups
@ -95,7 +93,7 @@ public class InternalGlobalOrdinalsBuilder extends AbstractIndexComponent implem
globalOrdToFirstSegmentDelta.freeze();
memorySizeInBytesCounter += globalOrdToFirstSegmentDelta.ramBytesUsed();
final long maxOrd = currentGlobalOrdinal + 1;
final long maxOrd = currentGlobalOrdinal;
OrdinalMappingSource[] segmentOrdToGlobalOrdLookups = ordinalMappingBuilder.build(maxOrd);
// add ram used for the main segmentOrd to globalOrd lookups
memorySizeInBytesCounter += ordinalMappingBuilder.getMemorySizeInBytes();
@ -163,7 +161,11 @@ public class InternalGlobalOrdinalsBuilder extends AbstractIndexComponent implem
@Override
public final long getOrd(int docId) {
long segmentOrd = segmentOrdinals.getOrd(docId);
return currentGlobalOrd = getGlobalOrd(segmentOrd);
if (segmentOrd == Ordinals.MISSING_ORDINAL) {
return currentGlobalOrd = Ordinals.MISSING_ORDINAL;
} else {
return currentGlobalOrd = getGlobalOrd(segmentOrd);
}
}
@Override
@ -189,7 +191,6 @@ public class InternalGlobalOrdinalsBuilder extends AbstractIndexComponent implem
segmentOrdToGlobalOrdDeltas = new MonotonicAppendingLongBuffer[numSegments];
for (int i = 0; i < segmentOrdToGlobalOrdDeltas.length; i++) {
segmentOrdToGlobalOrdDeltas[i] = new MonotonicAppendingLongBuffer(acceptableOverheadRatio);
segmentOrdToGlobalOrdDeltas[i].add(0);
}
this.numSegments = numSegments;
this.acceptableOverheadRatio = acceptableOverheadRatio;

View File

@ -51,13 +51,13 @@ public class MultiOrdinals implements Ordinals {
}
private final boolean multiValued;
private final long numOrds;
private final long maxOrd;
private final MonotonicAppendingLongBuffer endOffsets;
private final AppendingPackedLongBuffer ords;
public MultiOrdinals(OrdinalsBuilder builder, float acceptableOverheadRatio) {
multiValued = builder.getNumMultiValuesDocs() > 0;
numOrds = builder.getNumOrds();
maxOrd = builder.getMaxOrd();
endOffsets = new MonotonicAppendingLongBuffer(OFFSET_INIT_PAGE_COUNT, OFFSETS_PAGE_SIZE, acceptableOverheadRatio);
ords = new AppendingPackedLongBuffer(OFFSET_INIT_PAGE_COUNT, OFFSETS_PAGE_SIZE, acceptableOverheadRatio);
long lastEndOffset = 0;
@ -66,7 +66,7 @@ public class MultiOrdinals implements Ordinals {
final long endOffset = lastEndOffset + docOrds.length;
endOffsets.add(endOffset);
for (int j = 0; j < docOrds.length; ++j) {
ords.add(docOrds.longs[docOrds.offset + j] - 1);
ords.add(docOrds.longs[docOrds.offset + j]);
}
lastEndOffset = endOffset;
}
@ -86,7 +86,7 @@ public class MultiOrdinals implements Ordinals {
@Override
public long getMaxOrd() {
return numOrds + 1;
return maxOrd;
}
@Override
@ -98,7 +98,6 @@ public class MultiOrdinals implements Ordinals {
private final MonotonicAppendingLongBuffer endOffsets;
private final AppendingPackedLongBuffer ords;
private final LongsRef longsScratch;
private long offset;
private long limit;
private long currentOrd;
@ -107,7 +106,6 @@ public class MultiOrdinals implements Ordinals {
super(ordinals);
this.endOffsets = ordinals.endOffsets;
this.ords = ordinals.ords;
this.longsScratch = new LongsRef(16);
}
@Override
@ -115,16 +113,16 @@ public class MultiOrdinals implements Ordinals {
final long startOffset = docId > 0 ? endOffsets.get(docId - 1) : 0;
final long endOffset = endOffsets.get(docId);
if (startOffset == endOffset) {
return currentOrd = 0L; // ord for missing values
return currentOrd = Ordinals.MISSING_ORDINAL; // ord for missing values
} else {
return currentOrd = 1L + ords.get(startOffset);
return currentOrd = ords.get(startOffset);
}
}
@Override
public long nextOrd() {
assert offset < limit;
return currentOrd = 1L + ords.get(offset++);
return currentOrd = ords.get(offset++);
}
@Override

View File

@ -19,14 +19,16 @@
package org.elasticsearch.index.fielddata.ordinals;
import org.apache.lucene.index.SortedSetDocValues;
/**
* A thread safe ordinals abstraction. Ordinals can only be positive integers.
*/
public interface Ordinals {
static final long MISSING_ORDINAL = 0;
static final long MIN_ORDINAL = 1;
static final long MISSING_ORDINAL = SortedSetDocValues.NO_MORE_ORDS;
static final long MIN_ORDINAL = 0;
/**
* The memory size this ordinals take.

View File

@ -138,7 +138,7 @@ public final class OrdinalsBuilder implements Closeable {
// First level (0) of ordinals and pointers to the next level
private final GrowableWriter firstOrdinals;
private PagedGrowableWriter firstNextLevelSlices;
// Ordinals and pointers for other levels, starting at 1
// Ordinals and pointers for other levels +1
private final PagedGrowableWriter[] ordinals;
private final PagedGrowableWriter[] nextLevelSlices;
private final int[] sizes;
@ -181,7 +181,7 @@ public final class OrdinalsBuilder implements Closeable {
if (position == 0L) { // on the first level
// 0 or 1 ordinal
if (firstOrdinals.get(docID) == 0L) {
firstOrdinals.set(docID, ordinal);
firstOrdinals.set(docID, ordinal + 1);
return 1;
} else {
final long newSlice = newSlice(1);
@ -190,7 +190,7 @@ public final class OrdinalsBuilder implements Closeable {
}
firstNextLevelSlices.set(docID, newSlice);
final long offset = startOffset(1, newSlice);
ordinals[1].set(offset, ordinal);
ordinals[1].set(offset, ordinal + 1);
positions.set(docID, position(1, offset)); // current position is on the 1st level and not allocated yet
return 2;
}
@ -212,7 +212,7 @@ public final class OrdinalsBuilder implements Closeable {
// just go to the next slot
++offset;
}
ordinals[level].set(offset, ordinal);
ordinals[level].set(offset, ordinal + 1);
final long newPosition = position(level, offset);
positions.set(docID, newPosition);
return numOrdinals(level, offset);
@ -226,7 +226,7 @@ public final class OrdinalsBuilder implements Closeable {
return;
}
ords.longs = ArrayUtil.grow(ords.longs, ords.offset + ords.length + 1);
ords.longs[ords.offset + ords.length++] = firstOrd;
ords.longs[ords.offset + ords.length++] = firstOrd - 1;
if (firstNextLevelSlices == null) {
return;
}
@ -244,7 +244,7 @@ public final class OrdinalsBuilder implements Closeable {
if (ord == 0L) {
return;
}
ords.longs[ords.offset + ords.length++] = ord;
ords.longs[ords.offset + ords.length++] = ord - 1;
}
if (nextLevelSlices[level] == null) {
return;
@ -259,7 +259,7 @@ public final class OrdinalsBuilder implements Closeable {
}
private final int maxDoc;
private long currentOrd = 0;
private long currentOrd = Ordinals.MIN_ORDINAL - 1;
private int numDocsWithValue = 0;
private int numMultiValuedDocs = 0;
private int totalNumOrds = 0;
@ -295,7 +295,7 @@ public final class OrdinalsBuilder implements Closeable {
}
/**
* Return a {@link PackedInts.Reader} instance mapping every doc ID to its first ordinal if it exists and 0 otherwise.
* Return a {@link PackedInts.Reader} instance mapping every doc ID to its first ordinal + 1 if it exists and 0 otherwise.
*/
public PackedInts.Reader getFirstOrdinals() {
return ordinals.firstOrdinals;
@ -369,8 +369,8 @@ public final class OrdinalsBuilder implements Closeable {
/**
* Returns the number of distinct ordinals in this builder.
*/
public long getNumOrds() {
return currentOrd;
public long getMaxOrd() {
return currentOrd + 1;
}
/**
@ -395,7 +395,7 @@ public final class OrdinalsBuilder implements Closeable {
*/
public Ordinals build(Settings settings) {
final float acceptableOverheadRatio = settings.getAsFloat("acceptable_overhead_ratio", PackedInts.FASTEST);
if (numMultiValuedDocs > 0 || MultiOrdinals.significantlySmallerThanSinglePackedOrdinals(maxDoc, numDocsWithValue, getNumOrds(), acceptableOverheadRatio)) {
if (numMultiValuedDocs > 0 || MultiOrdinals.significantlySmallerThanSinglePackedOrdinals(maxDoc, numDocsWithValue, getMaxOrd(), acceptableOverheadRatio)) {
// MultiOrdinals can be smaller than SinglePackedOrdinals for sparse fields
return new MultiOrdinals(this, acceptableOverheadRatio);
} else {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.fielddata.ordinals;
import org.apache.lucene.util.LongsRef;
import org.apache.lucene.util.RamUsageEstimator;
import org.apache.lucene.util.packed.PackedInts;
@ -35,9 +34,9 @@ public class SinglePackedOrdinals implements Ordinals {
public SinglePackedOrdinals(OrdinalsBuilder builder, float acceptableOverheadRatio) {
assert builder.getNumMultiValuesDocs() == 0;
this.maxOrd = builder.getNumOrds() + 1;
this.maxOrd = builder.getMaxOrd();
// We don't reuse the builder as-is because it might have been built with a higher overhead ratio
final PackedInts.Mutable reader = PackedInts.getMutable(builder.maxDoc(), PackedInts.bitsRequired(getMaxOrd() - 1), acceptableOverheadRatio);
final PackedInts.Mutable reader = PackedInts.getMutable(builder.maxDoc(), PackedInts.bitsRequired(getMaxOrd()), acceptableOverheadRatio);
PackedInts.copy(builder.getFirstOrdinals(), 0, reader, 0, builder.maxDoc(), 8 * 1024);
this.reader = reader;
}
@ -69,7 +68,6 @@ public class SinglePackedOrdinals implements Ordinals {
private final PackedInts.Reader reader;
private final LongsRef longsScratch = new LongsRef(1);
private long currentOrdinal;
public Docs(SinglePackedOrdinals parent, PackedInts.Reader reader) {
@ -79,20 +77,20 @@ public class SinglePackedOrdinals implements Ordinals {
@Override
public long getOrd(int docId) {
return currentOrdinal = reader.get(docId);
return currentOrdinal = reader.get(docId) - 1;
}
@Override
public long nextOrd() {
assert currentOrdinal > 0;
assert currentOrdinal >= Ordinals.MIN_ORDINAL;
return currentOrdinal;
}
@Override
public int setDocument(int docId) {
currentOrdinal = reader.get(docId);
currentOrdinal = reader.get(docId) - 1;
// either this is > 1 or 0 - in any case it prevents a branch!
return (int)Math.min(currentOrdinal, 1);
return 1 + (int) Math.min(currentOrdinal, 0);
}
@Override

View File

@ -88,7 +88,6 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArra
// TODO: how can we guess the number of terms? numerics end up creating more terms per value...
final BigDoubleArrayList values = new BigDoubleArrayList();
values.add(0); // first "t" indicates null value
final float acceptableTransientOverheadRatio = fieldDataType.getSettings().getAsFloat("acceptable_transient_overhead_ratio", OrdinalsBuilder.DEFAULT_ACCEPTABLE_OVERHEAD_RATIO);
boolean success = false;
try (OrdinalsBuilder builder = new OrdinalsBuilder(reader.maxDoc(), acceptableTransientOverheadRatio)) {
@ -117,7 +116,12 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArra
int maxDoc = reader.maxDoc();
BigDoubleArrayList sValues = new BigDoubleArrayList(maxDoc);
for (int i = 0; i < maxDoc; i++) {
sValues.add(values.get(ordinals.getOrd(i)));
final long ordinal = ordinals.getOrd(i);
if (ordinal == Ordinals.MISSING_ORDINAL) {
sValues.add(0);
} else {
sValues.add(values.get(ordinal));
}
}
assert sValues.size() == maxDoc;
if (set == null) {

View File

@ -87,11 +87,8 @@ public class FSTBytesAtomicFieldData implements AtomicFieldData.WithOrdinals<Scr
if (hashes == null) {
BytesRefFSTEnum<Long> fstEnum = new BytesRefFSTEnum<>(fst);
IntArray hashes = BigArrays.NON_RECYCLING_INSTANCE.newIntArray(ordinals.getMaxOrd());
// we don't store an ord 0 in the FST since we could have an empty string in there and FST don't support
// empty strings twice. ie. them merge fails for long output.
hashes.set(0, new BytesRef().hashCode());
try {
for (long i = 1, maxOrd = ordinals.getMaxOrd(); i < maxOrd; ++i) {
for (long i = 0, maxOrd = ordinals.getMaxOrd(); i < maxOrd; ++i) {
hashes.set(i, fstEnum.next().input.hashCode());
}
assert fstEnum.next() == null;

View File

@ -93,7 +93,6 @@ public class FSTBytesIndexFieldData extends AbstractBytesIndexFieldData<FSTBytes
DocsEnum docsEnum = null;
for (BytesRef term = termsEnum.next(); term != null; term = termsEnum.next()) {
final long termOrd = builder.nextOrdinal();
assert termOrd > 0;
fstBuilder.add(Util.toIntsRef(term, scratch), (long) termOrd);
docsEnum = termsEnum.docs(null, docsEnum, DocsEnum.FLAG_NONE);
for (int docId = docsEnum.nextDoc(); docId != DocsEnum.NO_MORE_DOCS; docId = docsEnum.nextDoc()) {

View File

@ -86,8 +86,6 @@ public class FloatArrayIndexFieldData extends AbstractIndexFieldData<FloatArrayA
// TODO: how can we guess the number of terms? numerics end up creating more terms per value...
final BigFloatArrayList values = new BigFloatArrayList();
values.add(0); // first "t" indicates null value
final float acceptableTransientOverheadRatio = fieldDataType.getSettings().getAsFloat("acceptable_transient_overhead_ratio", OrdinalsBuilder.DEFAULT_ACCEPTABLE_OVERHEAD_RATIO);
boolean success = false;
try (OrdinalsBuilder builder = new OrdinalsBuilder(reader.maxDoc(), acceptableTransientOverheadRatio)) {
@ -116,7 +114,12 @@ public class FloatArrayIndexFieldData extends AbstractIndexFieldData<FloatArrayA
int maxDoc = reader.maxDoc();
BigFloatArrayList sValues = new BigFloatArrayList(maxDoc);
for (int i = 0; i < maxDoc; i++) {
sValues.add(values.get(ordinals.getOrd(i)));
final long ordinal = ordinals.getOrd(i);
if (ordinal == Ordinals.MISSING_ORDINAL) {
sValues.add(0);
} else {
sValues.add(values.get(ordinal));
}
}
assert sValues.size() == maxDoc;
if (set == null) {

View File

@ -100,7 +100,6 @@ public abstract class GeoPointCompressedAtomicFieldData extends AtomicGeoPointFi
@Override
public GeoPoint nextValue() {
final long ord = ordinals.nextOrd();
assert ord > 0;
return encoding.decode(lat.get(ord), lon.get(ord), scratch);
}

View File

@ -103,9 +103,8 @@ public class GeoPointCompressedIndexFieldData extends AbstractGeoPointIndexField
try (OrdinalsBuilder builder = new OrdinalsBuilder(terms.size(), reader.maxDoc(), acceptableTransientOverheadRatio)) {
final GeoPointEnum iter = new GeoPointEnum(builder.buildFromTerms(terms.iterator(null)));
GeoPoint point;
long ord = 0;
while ((point = iter.next()) != null) {
++ord;
final long ord = builder.currentOrdinal();
if (lat.size() <= ord) {
final long newSize = BigArrays.overSize(ord + 1);
lat = lat.resize(newSize);
@ -127,10 +126,16 @@ public class GeoPointCompressedIndexFieldData extends AbstractGeoPointIndexField
int maxDoc = reader.maxDoc();
PagedMutable sLat = new PagedMutable(reader.maxDoc(), pageSize, encoding.numBitsPerCoordinate(), PackedInts.COMPACT);
PagedMutable sLon = new PagedMutable(reader.maxDoc(), pageSize, encoding.numBitsPerCoordinate(), PackedInts.COMPACT);
final long missing = encoding.encodeCoordinate(0);
for (int i = 0; i < maxDoc; i++) {
final long nativeOrdinal = ordinals.getOrd(i);
sLat.set(i, lat.get(nativeOrdinal));
sLon.set(i, lon.get(nativeOrdinal));
if (nativeOrdinal != Ordinals.MISSING_ORDINAL) {
sLat.set(i, lat.get(nativeOrdinal));
sLon.set(i, lon.get(nativeOrdinal));
} else {
sLat.set(i, missing);
sLon.set(i, missing);
}
}
FixedBitSet set = builder.buildDocsWithValuesSet();
if (set == null) {

View File

@ -94,7 +94,6 @@ public abstract class GeoPointDoubleArrayAtomicFieldData extends AtomicGeoPointF
@Override
public GeoPoint nextValue() {
final long ord = ordinals.nextOrd();
assert ord > 0;
return scratch.reset(lat.get(ord), lon.get(ord));
}

View File

@ -72,8 +72,6 @@ public class GeoPointDoubleArrayIndexFieldData extends AbstractGeoPointIndexFiel
}
final BigDoubleArrayList lat = new BigDoubleArrayList();
final BigDoubleArrayList lon = new BigDoubleArrayList();
lat.add(0); // first "t" indicates null value
lon.add(0); // first "t" indicates null value
final float acceptableTransientOverheadRatio = fieldDataType.getSettings().getAsFloat("acceptable_transient_overhead_ratio", OrdinalsBuilder.DEFAULT_ACCEPTABLE_OVERHEAD_RATIO);
boolean success = false;
try (OrdinalsBuilder builder = new OrdinalsBuilder(terms.size(), reader.maxDoc(), acceptableTransientOverheadRatio)) {
@ -92,8 +90,13 @@ public class GeoPointDoubleArrayIndexFieldData extends AbstractGeoPointIndexFiel
BigDoubleArrayList sLon = new BigDoubleArrayList(reader.maxDoc());
for (int i = 0; i < maxDoc; i++) {
long nativeOrdinal = ordinals.getOrd(i);
sLat.add(lat.get(nativeOrdinal));
sLon.add(lon.get(nativeOrdinal));
if (nativeOrdinal == Ordinals.MISSING_ORDINAL) {
sLat.add(0);
sLon.add(0);
} else {
sLat.add(lat.get(nativeOrdinal));
sLon.add(lon.get(nativeOrdinal));
}
}
FixedBitSet set = builder.buildDocsWithValuesSet();
if (set == null) {

View File

@ -135,7 +135,7 @@ public abstract class PackedArrayAtomicFieldData extends AbstractAtomicNumericFi
@Override
public long getValueByOrd(long ord) {
assert ord != Ordinals.MISSING_ORDINAL;
return values.get(ord - 1);
return values.get(ord);
}
}
@ -151,7 +151,7 @@ public abstract class PackedArrayAtomicFieldData extends AbstractAtomicNumericFi
@Override
public double getValueByOrd(long ord) {
assert ord != Ordinals.MISSING_ORDINAL;
return values.get(ord - 1);
return values.get(ord);
}

View File

@ -186,7 +186,7 @@ public class PackedArrayIndexFieldData extends AbstractIndexFieldData<AtomicNume
for (int i = 0; i < reader.maxDoc(); i++) {
final long ord = ordinals.getOrd(i);
if (ord != Ordinals.MISSING_ORDINAL) {
long value = values.get(ord - 1);
long value = values.get(ord);
sValues.set(i, value - minValue);
}
}
@ -204,7 +204,7 @@ public class PackedArrayIndexFieldData extends AbstractIndexFieldData<AtomicNume
for (int i = 0; i < reader.maxDoc(); i++) {
final long ord = ordinals.getOrd(i);
if (ord != Ordinals.MISSING_ORDINAL) {
lastValue = values.get(ord - 1);
lastValue = values.get(ord);
}
dpValues.add(lastValue);
}
@ -305,8 +305,8 @@ public class PackedArrayIndexFieldData extends AbstractIndexFieldData<AtomicNume
pageMemorySize += RamUsageEstimator.alignObjectSize(RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + RamUsageEstimator.NUM_BYTES_INT);
} else {
long pageMinValue = values.get(pageMinOrdinal - 1);
long pageMaxValue = values.get(pageMaxOrdinal - 1);
long pageMinValue = values.get(pageMinOrdinal);
long pageMaxValue = values.get(pageMaxOrdinal);
long pageDelta = pageMaxValue - pageMinValue;
if (pageDelta != 0) {
bitsRequired = pageDelta < 0 ? 64 : PackedInts.bitsRequired(pageDelta);

View File

@ -39,7 +39,6 @@ public class PagedBytesAtomicFieldData implements AtomicFieldData.WithOrdinals<S
return new Empty();
}
// 0 ordinal in values means no value (its null)
private final PagedBytes.Reader bytes;
private final MonotonicAppendingLongBuffer termOrdToBytesOffset;
protected final Ordinals ordinals;

View File

@ -76,7 +76,6 @@ public class PagedBytesIndexFieldData extends AbstractBytesIndexFieldData<PagedB
final PagedBytes bytes = new PagedBytes(15);
final MonotonicAppendingLongBuffer termOrdToBytesOffset = new MonotonicAppendingLongBuffer();
termOrdToBytesOffset.add(0); // first ord is reserved for missing values
final long numTerms;
if (regex == null && frequency == null) {
numTerms = terms.size();

View File

@ -188,9 +188,6 @@ public class ParentChildIndexFieldData extends AbstractIndexFieldData<ParentChil
TypeBuilder(float acceptableTransientOverheadRatio, AtomicReader reader) throws IOException {
bytes = new PagedBytes(15);
termOrdToBytesOffset = new MonotonicAppendingLongBuffer();
termOrdToBytesOffset.add(0); // first ord is reserved for missing values
// 0 is reserved for "unset"
bytes.copyUsingLengthPrefix(new BytesRef());
builder = new OrdinalsBuilder(-1, reader.maxDoc(), acceptableTransientOverheadRatio);
}
}

View File

@ -20,7 +20,6 @@
package org.elasticsearch.index.fielddata.plain;
import org.apache.lucene.index.AtomicReader;
import org.apache.lucene.index.FilterAtomicReader;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.util.ArrayUtil;
@ -56,10 +55,6 @@ abstract class SortedSetDVAtomicFieldData {
return true;
}
public int getNumDocs() {
return reader.maxDoc();
}
public long getNumberUniqueValues() {
final SortedSetDocValues values = getValuesNoException(reader, field);
return values.getValueCount();
@ -86,12 +81,11 @@ abstract class SortedSetDVAtomicFieldData {
synchronized (this) {
if (hashes == null) {
final long valueCount = values.getValueCount();
final IntArray hashes = BigArrays.NON_RECYCLING_INSTANCE.newIntArray(1L + valueCount);
final IntArray hashes = BigArrays.NON_RECYCLING_INSTANCE.newIntArray(valueCount);
BytesRef scratch = new BytesRef(16);
hashes.set(0, scratch.hashCode());
for (long i = 0; i < valueCount; ++i) {
values.lookupOrd(i, scratch);
hashes.set(1L + i, scratch.hashCode());
hashes.set(i, scratch.hashCode());
}
this.hashes = hashes;
}
@ -101,20 +95,7 @@ abstract class SortedSetDVAtomicFieldData {
}
public TermsEnum getTermsEnum() {
final TermsEnum termsEnum = getValuesNoException(reader, field).termsEnum();
return new FilterAtomicReader.FilterTermsEnum(termsEnum) {
@Override
public void seekExact(long ord) throws IOException {
super.seekExact(ord - 1);
}
@Override
public long ord() throws IOException {
return super.ord() + 1;
}
};
return getValuesNoException(reader, field).termsEnum();
}
private static SortedSetDocValues getValuesNoException(AtomicReader reader, String field) {
@ -143,13 +124,13 @@ abstract class SortedSetDVAtomicFieldData {
@Override
public BytesRef getValueByOrd(long ord) {
assert ord != Ordinals.MISSING_ORDINAL;
values.lookupOrd(ord - 1, scratch);
values.lookupOrd(ord, scratch);
return scratch;
}
@Override
public BytesRef nextValue() {
values.lookupOrd(ordinals.nextOrd()-1, scratch);
values.lookupOrd(ordinals.nextOrd(), scratch);
return scratch;
}
}
@ -175,13 +156,13 @@ abstract class SortedSetDVAtomicFieldData {
// We don't store SortedSetDocValues as a member because Ordinals must be thread-safe
private final AtomicReader reader;
private final String field;
private final long numOrds;
private final long maxOrd;
public SortedSetOrdinals(AtomicReader reader, String field, long numOrds) {
super();
this.reader = reader;
this.field = field;
this.numOrds = numOrds;
this.maxOrd = numOrds;
}
@Override
@ -197,13 +178,13 @@ abstract class SortedSetDVAtomicFieldData {
@Override
public long getMaxOrd() {
return 1 + numOrds;
return maxOrd;
}
@Override
public Docs ordinals() {
final SortedSetDocValues values = getValuesNoException(reader, field);
assert values.getValueCount() == numOrds;
assert values.getValueCount() == maxOrd;
return new SortedSetDocs(this, values);
}
@ -225,7 +206,7 @@ abstract class SortedSetDVAtomicFieldData {
@Override
public long getOrd(int docId) {
values.setDocument(docId);
return currentOrdinal = 1 + values.nextOrd();
return currentOrdinal = values.nextOrd();
}
@Override
@ -242,7 +223,7 @@ abstract class SortedSetDVAtomicFieldData {
int i = 0;
for (long ord = values.nextOrd(); ord != SortedSetDocValues.NO_MORE_ORDS; ord = values.nextOrd()) {
ords = ArrayUtil.grow(ords, i + 1);
ords[i++] = ord + Ordinals.MIN_ORDINAL;
ords[i++] = ord;
}
ordIndex = 0;
return i;

View File

@ -205,8 +205,8 @@ public class TermsStringOrdinalsFacetExecutor extends FacetExecutor {
@Override
public void setNextReader(AtomicReaderContext context) throws IOException {
if (current != null) {
missing += current.counts.get(0);
total += current.total - current.counts.get(0);
missing += current.missing;
total += current.total;
if (current.values.ordinals().getMaxOrd() > Ordinals.MIN_ORDINAL) {
aggregators.add(current);
} else {
@ -232,8 +232,8 @@ public class TermsStringOrdinalsFacetExecutor extends FacetExecutor {
@Override
public void postCollection() {
if (current != null) {
missing += current.counts.get(0);
total += current.total - current.counts.get(0);
missing += current.missing;
total += current.total;
// if we have values for this one, add it
if (current.values.ordinals().getMaxOrd() > Ordinals.MIN_ORDINAL) {
aggregators.add(current);
@ -253,7 +253,8 @@ public class TermsStringOrdinalsFacetExecutor extends FacetExecutor {
final BytesValues.WithOrdinals values;
final IntArray counts;
long position = 0;
int missing = 0;
long position = Ordinals.MIN_ORDINAL - 1;
BytesRef current;
int total;
@ -270,8 +271,7 @@ public class TermsStringOrdinalsFacetExecutor extends FacetExecutor {
}
final void incrementMissing(int numMissing) {
counts.increment(0, numMissing);
total += numMissing;
missing += numMissing;
}
public boolean nextPosition() {

View File

@ -439,15 +439,15 @@ public abstract class AbstractStringFieldDataTests extends AbstractFieldDataImpl
Ordinals.Docs ordinals = afd.getBytesValues(randomBoolean()).ordinals();
assertThat(ordinals.setDocument(0), equalTo(2));
long ord = ordinals.nextOrd();
assertThat(ord, equalTo(4l));
assertThat(ord, equalTo(3l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("02"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(6l));
assertThat(ord, equalTo(5l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("04"));
assertThat(ordinals.setDocument(1), equalTo(0));
assertThat(ordinals.setDocument(2), equalTo(1));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(5l));
assertThat(ord, equalTo(4l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("03"));
// Second segment
@ -456,34 +456,34 @@ public abstract class AbstractStringFieldDataTests extends AbstractFieldDataImpl
ordinals = afd.getBytesValues(randomBoolean()).ordinals();
assertThat(ordinals.setDocument(0), equalTo(3));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(6l));
assertThat(ord, equalTo(5l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("04"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(7l));
assertThat(ord, equalTo(6l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("05"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(8l));
assertThat(ord, equalTo(7l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("06"));
assertThat(ordinals.setDocument(1), equalTo(3));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(8l));
assertThat(ord, equalTo(7l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("06"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(9l));
assertThat(ord, equalTo(8l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("07"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(10l));
assertThat(ord, equalTo(9l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("08"));
assertThat(ordinals.setDocument(2), equalTo(0));
assertThat(ordinals.setDocument(3), equalTo(3));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(10l));
assertThat(ord, equalTo(9l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("08"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(11l));
assertThat(ord, equalTo(10l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("09"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(12l));
assertThat(ord, equalTo(11l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("10"));
// Third segment
@ -492,13 +492,13 @@ public abstract class AbstractStringFieldDataTests extends AbstractFieldDataImpl
ordinals = afd.getBytesValues(randomBoolean()).ordinals();
assertThat(ordinals.setDocument(0), equalTo(3));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(1l));
assertThat(ord, equalTo(0l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("!08"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(2l));
assertThat(ord, equalTo(1l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("!09"));
ord = ordinals.nextOrd();
assertThat(ord, equalTo(3l));
assertThat(ord, equalTo(2l));
assertThat(values.getValueByOrd(ord).utf8ToString(), equalTo("!10"));
}
@ -529,7 +529,7 @@ public abstract class AbstractStringFieldDataTests extends AbstractFieldDataImpl
}
assertThat(size, equalTo(2));
termsEnum.seekExact(9);
termsEnum.seekExact(8);
assertThat(termsEnum.term().utf8ToString(), equalTo("07"));
size = 0;
while (termsEnum.next() != null) {

View File

@ -74,9 +74,9 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(3L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(2).utf8ToString(), equalTo("100"));
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("100"));
}
{
ifdService.clear();
@ -86,8 +86,8 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("5"));
assertThat(1L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("5"));
}
{
@ -98,9 +98,9 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(3L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(2).utf8ToString(), equalTo("100"));
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("100"));
}
{
@ -111,9 +111,9 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(3L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(2).utf8ToString(), equalTo("100"));
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("100"));
}
{
@ -127,8 +127,8 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("100"));
assertThat(1L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("100"));
}
}
@ -171,8 +171,8 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("5"));
assertThat(1L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("5"));
}
{
ifdService.clear();
@ -182,9 +182,9 @@ public class FilterFieldDataTest extends AbstractFieldDataTests {
AtomicFieldData.WithOrdinals<ScriptDocValues.Strings> loadDirect = (WithOrdinals<Strings>) fieldData.loadDirect(context);
BytesValues.WithOrdinals bytesValues = loadDirect.getBytesValues(randomBoolean());
Docs ordinals = bytesValues.ordinals();
assertThat(3L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(2).utf8ToString(), equalTo("5"));
assertThat(2L, equalTo(ordinals.getMaxOrd()));
assertThat(bytesValues.getValueByOrd(0).utf8ToString(), equalTo("10"));
assertThat(bytesValues.getValueByOrd(1).utf8ToString(), equalTo("5"));
}
}

View File

@ -51,7 +51,7 @@ public class MultiOrdinalsTests extends ElasticsearchTestCase {
OrdinalsBuilder builder = new OrdinalsBuilder(numDocs);
Set<OrdAndId> ordsAndIdSet = new HashSet<>();
for (int i = 0; i < numValues; i++) {
ordsAndIdSet.add(new OrdAndId(1 + random.nextInt(numOrdinals), random.nextInt(numDocs)));
ordsAndIdSet.add(new OrdAndId(random.nextInt(numOrdinals), random.nextInt(numDocs)));
}
List<OrdAndId> ordsAndIds = new ArrayList<>(ordsAndIdSet);
Collections.sort(ordsAndIds, new Comparator<OrdAndId>() {
@ -181,31 +181,31 @@ public class MultiOrdinalsTests extends ElasticsearchTestCase {
int maxDoc = 7;
long maxOrds = 32;
OrdinalsBuilder builder = new OrdinalsBuilder(maxDoc);
builder.nextOrdinal(); // 1
builder.nextOrdinal(); // 0
builder.addDoc(1).addDoc(4).addDoc(5).addDoc(6);
builder.nextOrdinal(); // 2
builder.nextOrdinal(); // 1
builder.addDoc(0).addDoc(5).addDoc(6);
builder.nextOrdinal(); // 3
builder.addDoc(2).addDoc(4).addDoc(5).addDoc(6);
builder.nextOrdinal(); // 4
builder.nextOrdinal(); // 3
builder.addDoc(0).addDoc(4).addDoc(5).addDoc(6);
builder.nextOrdinal(); // 4
builder.addDoc(4).addDoc(5).addDoc(6);
builder.nextOrdinal(); // 5
builder.addDoc(4).addDoc(5).addDoc(6);
long ord = builder.nextOrdinal(); // 6
builder.addDoc(4).addDoc(5).addDoc(6);
for (long i = ord; i < maxOrds; i++) {
while (builder.getMaxOrd() < maxOrds) {
builder.nextOrdinal();
builder.addDoc(5).addDoc(6);
}
long[][] ordinalPlan = new long[][]{
{2, 4},
{1},
{3},
{1, 3},
{0},
{2},
{},
{1, 3, 4, 5, 6},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
{0, 2, 3, 4, 5},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}
};
Ordinals ordinals = creationMultiOrdinals(builder);
@ -251,13 +251,13 @@ public class MultiOrdinalsTests extends ElasticsearchTestCase {
}
long[][] ordinalPlan = new long[][]{
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
{0},
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4, 5},
{1},
{1, 2, 3, 4, 5},
{1, 2, 3, 4, 5, 6},
{2},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
};
Ordinals ordinals = new MultiOrdinals(builder, PackedInts.FASTEST);
@ -266,14 +266,13 @@ public class MultiOrdinalsTests extends ElasticsearchTestCase {
}
private void assertEquals(Ordinals.Docs docs, long[][] ordinalPlan) {
long numOrds = 0;
long maxOrd = 0;
for (int doc = 0; doc < ordinalPlan.length; ++doc) {
if (ordinalPlan[doc].length > 0) {
numOrds = Math.max(numOrds, ordinalPlan[doc][ordinalPlan[doc].length - 1]);
maxOrd = Math.max(maxOrd, 1 + ordinalPlan[doc][ordinalPlan[doc].length - 1]);
}
}
assertThat(docs.getMaxOrd(), equalTo(numOrds + Ordinals.MIN_ORDINAL)); // Includes null ord
assertThat(docs.getMaxOrd(), equalTo(numOrds + 1));
assertThat(docs.getMaxOrd(), equalTo(maxOrd));
assertThat(docs.isMultiValued(), equalTo(true));
for (int doc = 0; doc < ordinalPlan.length; ++doc) {
long[] ords = ordinalPlan[doc];