Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ public BlockLoader blockLoader(BlockLoaderContext blContext) {
return BlockLoader.CONSTANT_NULLS;
}
if (hasDocValues() && (blContext.fieldExtractPreference() != FieldExtractPreference.STORED || isSyntheticSource)) {
return new BlockDocValuesReader.DoublesBlockLoader(name(), l -> l / scalingFactor);
return new BlockDocValuesReader.DoublesBlockLoader(name(), new BlockDocValuesReader.LongToScaledFloat(scalingFactor));
}
// Multi fields don't have fallback synthetic source.
if (isSyntheticSource && blContext.parentField(name()) == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.apache.lucene.util.packed.PackedInts;
import org.elasticsearch.core.IOUtils;
import org.elasticsearch.index.codec.tsdb.TSDBDocValuesEncoder;
import org.elasticsearch.index.mapper.BlockDocValuesReader;
import org.elasticsearch.index.mapper.BlockLoader;

import java.io.IOException;
Expand Down Expand Up @@ -515,7 +516,7 @@ BlockLoader.Block tryRead(BlockLoader.SingletonLongBuilder builder, BlockLoader.
}
}

abstract static class BaseSparseNumericValues extends NumericDocValues {
abstract static class BaseSparseNumericValues extends NumericDocValues implements BlockDocValuesReader.OptionalSingletonDoubles {
protected final IndexedDISI disi;

BaseSparseNumericValues(IndexedDISI disi) {
Expand Down Expand Up @@ -546,6 +547,17 @@ public final int docID() {
public final long cost() {
return disi.cost();
}

@Override
public BlockLoader.Block tryReadDoubles(
BlockLoader.BlockFactory factory,
BlockLoader.Docs docs,
int offset,
BlockDocValuesReader.ToDouble toDouble,
boolean nullsFiltered
) throws IOException {
return null;
}
}

abstract static class BaseSortedSetDocValues extends SortedSetDocValues {
Expand Down Expand Up @@ -1456,6 +1468,7 @@ static boolean isDense(int firstDocId, int lastDocId, int length) {
);
return new BaseSparseNumericValues(disi) {
private final TSDBDocValuesEncoder decoder = new TSDBDocValuesEncoder(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE);
private IndexedDISI jumpDISI;
private long currentBlockIndex = -1;
private final long[] currentBlock = new long[ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE];

Expand All @@ -1479,6 +1492,69 @@ public long longValue() throws IOException {
}
return currentBlock[blockInIndex];
}

@Override
public BlockLoader.Block tryReadDoubles(
BlockLoader.BlockFactory factory,
BlockLoader.Docs docs,
int offset,
BlockDocValuesReader.ToDouble toDouble,
boolean nullsFiltered
) throws IOException {
if (nullsFiltered == false) {
return null;
}
final int firstDoc = docs.get(offset);
if (disi.advanceExact(firstDoc) == false) {
assert false : "nullsFiltered is true, but doc [" + firstDoc + "] has no value";
throw new IllegalStateException("nullsFiltered is true, but doc [" + firstDoc + "] has no value");
}
if (jumpDISI == null) {
jumpDISI = new IndexedDISI(
data,
entry.docsWithFieldOffset,
entry.docsWithFieldLength,
entry.jumpTableEntryCount,
entry.denseRankPower,
entry.numValues
);
}
final int lastDoc = docs.get(docs.count() - 1);
if (jumpDISI.advanceExact(lastDoc) == false) {
assert false : "nullsFiltered is true, but doc [" + lastDoc + "] has no value";
throw new IllegalStateException("nullsFiltered is true, but doc [" + lastDoc + "] has no value");
}
// Assumes docIds are unique - if the number of value indices between the first
// and last doc equals the doc count, all values can be read and converted in bulk
// TODO: Pass docCount attr for enrich and lookup.
final int firstIndex = disi.index();
final int lastIndex = jumpDISI.index();
final int valueCount = lastIndex - firstIndex + 1;
// TODO: encode this via docCount
if (valueCount == docs.count()) {
final double[] values = new double[valueCount];
int i = 0;
while (i < valueCount) {
final int index = firstIndex + i;
final int blockIndex = index >>> ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SHIFT;
final int blockStartIndex = index & ES819TSDBDocValuesFormat.NUMERIC_BLOCK_MASK;
if (blockIndex != currentBlockIndex) {
assert blockIndex > currentBlockIndex : blockIndex + "<=" + currentBlockIndex;
if (currentBlockIndex + 1 != blockIndex) {
valuesData.seek(indexReader.get(blockIndex));
}
currentBlockIndex = blockIndex;
decoder.decode(valuesData, currentBlock);
}
// bulk convert from the
final int count = Math.min(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE - blockStartIndex, valueCount - i);
toDouble.convert(currentBlock, blockStartIndex, values, i, count);
i += count;
}
return factory.doubles(values, docs.count());
}
return null;
}
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.sandbox.document.HalfFloatPoint;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.io.stream.ByteArrayStreamInput;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.index.mapper.BlockLoader.BlockFactory;
import org.elasticsearch.index.mapper.BlockLoader.BooleanBuilder;
Expand Down Expand Up @@ -143,6 +146,7 @@ public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boole
if (numericDocValues.advanceExact(doc)) {
builder.appendLong(numericDocValues.longValue());
} else {
assert nullsFiltered == false : "nullFiltered is true, but doc [" + doc + "] has no value";
builder.appendNull();
}
}
Expand Down Expand Up @@ -348,11 +352,133 @@ public String toString() {

/**
* Convert from the stored {@link long} into the {@link double} to load.
* Sadly, this will go megamorphic pretty quickly and slow us down,
* but it gets the job done for now.
*/
public interface ToDouble {
public sealed interface ToDouble {
double convert(long v);

void convert(long[] src, int srcOffset, double[] dst, int dstOff, int count);

BlockLoader.Block readThenConvert(BlockFactory factory, NumericDocValues dv, Docs docs, int offset) throws IOException;

ToDouble SORTABLE_SHORT_TO_HALF_FLOAT = new SortableShortToHalfFloat();
ToDouble SORTABLE_INT_TO_FLOAT = new SortableIntToFloat();
ToDouble SORTABLE_LONG_TO_DOUBLE = new SortableLongToDouble();
}

private static final class SortableShortToHalfFloat implements ToDouble {
@Override
public double convert(long v) {
return HalfFloatPoint.sortableShortToHalfFloat((short) v);
}

@Override
public void convert(long[] src, int srcOffset, double[] dst, int dstOff, int count) {
for (int i = 0; i < count; i++) {
dst[dstOff + i] = HalfFloatPoint.sortableShortToHalfFloat((short) src[srcOffset + i]);
}
}

@Override
public BlockLoader.Block readThenConvert(BlockFactory factory, NumericDocValues dv, Docs docs, int offset) throws IOException {
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
for (int i = offset; i < docs.count(); i++) {
int doc = docs.get(i);
if (dv.advanceExact(doc)) {
builder.appendDouble(HalfFloatPoint.sortableShortToHalfFloat((short) dv.longValue()));
} else {
builder.appendNull();
}
}
return builder.build();
}
}
}

private static final class SortableIntToFloat implements BlockDocValuesReader.ToDouble {
@Override
public double convert(long v) {
return NumericUtils.sortableIntToFloat((int) v);
}

@Override
public void convert(long[] src, int srcOffset, double[] dst, int dstOff, int count) {
for (int i = 0; i < count; i++) {
dst[dstOff + i] = NumericUtils.sortableIntToFloat((int) src[srcOffset + i]);
}
}

@Override
public BlockLoader.Block readThenConvert(BlockFactory factory, NumericDocValues dv, Docs docs, int offset) throws IOException {
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
for (int i = offset; i < docs.count(); i++) {
int doc = docs.get(i);
if (dv.advanceExact(doc)) {
builder.appendDouble(NumericUtils.sortableIntToFloat((int) dv.longValue()));
} else {
builder.appendNull();
}
}
return builder.build();
}
}
}

private static final class SortableLongToDouble implements BlockDocValuesReader.ToDouble {
@Override
public double convert(long v) {
return NumericUtils.sortableLongToDouble(v);
}

@Override
public void convert(long[] src, int srcOffset, double[] dst, int dstOff, int count) {
for (int i = 0; i < count; i++) {
dst[dstOff + i] = NumericUtils.sortableLongToDouble(src[srcOffset + i]);
}
}

@Override
public BlockLoader.Block readThenConvert(BlockFactory factory, NumericDocValues dv, Docs docs, int offset) throws IOException {
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
for (int i = offset; i < docs.count(); i++) {
int doc = docs.get(i);
if (dv.advanceExact(doc)) {
builder.appendDouble(NumericUtils.sortableLongToDouble(dv.longValue()));
} else {
builder.appendNull();
}
}
return builder.build();
}
}
}

public record LongToScaledFloat(double scalingFactor) implements ToDouble {
@Override
public double convert(long v) {
return v / scalingFactor;
}

@Override
public void convert(long[] src, int srcOffset, double[] dst, int dstOff, int count) {
for (int i = 0; i < count; i++) {
dst[dstOff + i] = src[srcOffset + i] / scalingFactor;
}
}

@Override
public BlockLoader.Block readThenConvert(BlockFactory factory, NumericDocValues dv, Docs docs, int offset) throws IOException {
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
for (int i = offset; i < docs.count(); i++) {
int doc = docs.get(i);
if (dv.advanceExact(doc)) {
builder.appendDouble(dv.longValue() / scalingFactor);
} else {
builder.appendNull();
}
}
return builder.build();
}
}
}

public static class DoublesBlockLoader extends DocValuesBlockLoader {
Expand Down Expand Up @@ -387,6 +513,21 @@ public AllReader reader(LeafReaderContext context) throws IOException {
}
}

public interface OptionalSingletonDoubles {
/**
* Attempts to read the values of all documents in {@code docs} and convert them to doubles.
* Returns {@code null} if unable to load the values.
*/
@Nullable
BlockLoader.Block tryReadDoubles(
BlockFactory factory,
Docs docs,
int offset,
BlockDocValuesReader.ToDouble toDouble,
boolean nullsFiltered
) throws IOException;
}

private static class SingletonDoubles extends BlockDocValuesReader {
private final NumericDocValues docValues;
private final ToDouble toDouble;
Expand All @@ -398,17 +539,13 @@ private static class SingletonDoubles extends BlockDocValuesReader {

@Override
public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boolean nullsFiltered) throws IOException {
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
for (int i = offset; i < docs.count(); i++) {
int doc = docs.get(i);
if (docValues.advanceExact(doc)) {
builder.appendDouble(toDouble.convert(docValues.longValue()));
} else {
builder.appendNull();
}
if (docValues instanceof OptionalSingletonDoubles direct) {
BlockLoader.Block block = direct.tryReadDoubles(factory, docs, offset, toDouble, nullsFiltered);
if (block != null) {
return block;
}
return builder.build();
}
return toDouble.readThenConvert(factory, docValues, docs, offset);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,11 @@ interface BlockFactory {
*/
DoubleBuilder doubles(int expectedCount);

/**
* Creates a block from an array of doubles
*/
Block doubles(double[] values, int expectedCount);

/**
* Build a builder to load dense vectors without any loading constraints.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ public void writeValue(XContentBuilder b, long value) throws IOException {

@Override
BlockLoader blockLoaderFromDocValues(String fieldName) {
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, l -> HalfFloatPoint.sortableShortToHalfFloat((short) l));
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, BlockDocValuesReader.ToDouble.SORTABLE_SHORT_TO_HALF_FLOAT);
}

@Override
Expand Down Expand Up @@ -677,7 +677,7 @@ public void writeValue(XContentBuilder b, long value) throws IOException {

@Override
BlockLoader blockLoaderFromDocValues(String fieldName) {
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, l -> NumericUtils.sortableIntToFloat((int) l));
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, BlockDocValuesReader.ToDouble.SORTABLE_INT_TO_FLOAT);
}

@Override
Expand Down Expand Up @@ -837,7 +837,7 @@ public void writeValue(XContentBuilder b, long value) throws IOException {

@Override
BlockLoader blockLoaderFromDocValues(String fieldName) {
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, NumericUtils::sortableLongToDouble);
return new BlockDocValuesReader.DoublesBlockLoader(fieldName, BlockDocValuesReader.ToDouble.SORTABLE_LONG_TO_DOUBLE);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ public DoublesBuilder appendDouble(double value) {
return new DoublesBuilder();
}

@Override
public BlockLoader.Block doubles(double[] values, int expectedCount) {
try (BlockLoader.DoubleBuilder builder = doubles(expectedCount)) {
for (double value : values) {
builder.appendDouble(value);
}
return builder.build();
}
}

@Override
public BlockLoader.FloatBuilder denseVectors(int expectedCount, int dimensions) {
class FloatsBuilder extends TestBlock.Builder implements BlockLoader.FloatBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public BlockLoader.DoubleBuilder doubles(int expectedCount) {
return factory.newDoubleBlockBuilder(expectedCount);
}

@Override
public BlockLoader.Block doubles(double[] values, int expectedCount) {
return factory.newDoubleArrayVector(values, expectedCount).asBlock();
}

@Override
public BlockLoader.FloatBuilder denseVectors(int expectedVectorsCount, int dimensions) {
return factory.newFloatBlockBuilder(expectedVectorsCount * dimensions);
Expand Down