Skip to content

Commit b15bf8a

Browse files
committed
Push down loading of singleton dense double based field types to the es819 doc value codec
1 parent 69f1e2a commit b15bf8a

File tree

10 files changed

+206
-3
lines changed

10 files changed

+206
-3
lines changed

server/src/main/java/org/elasticsearch/index/codec/tsdb/es819/ES819TSDBDocValuesProducer.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.apache.lucene.util.packed.PackedInts;
4646
import org.elasticsearch.core.IOUtils;
4747
import org.elasticsearch.index.codec.tsdb.TSDBDocValuesEncoder;
48+
import org.elasticsearch.index.mapper.BlockDocValuesReader;
4849
import org.elasticsearch.index.mapper.BlockLoader;
4950

5051
import java.io.IOException;
@@ -1371,6 +1372,19 @@ public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.D
13711372
}
13721373
}
13731374

1375+
@Override
1376+
public BlockLoader.Block tryReadDoubles(
1377+
BlockLoader.BlockFactory factory,
1378+
BlockLoader.Docs docs,
1379+
int offset,
1380+
BlockDocValuesReader.ToDouble toDouble
1381+
) throws IOException {
1382+
try (BlockLoader.SingletonLongBuilder builder = factory.singletonLongs(docs.count() - offset)) {
1383+
builder.setToDouble(toDouble);
1384+
return tryRead(builder, docs, offset);
1385+
}
1386+
}
1387+
13741388
@Override
13751389
BlockLoader.Block tryRead(BlockLoader.SingletonLongBuilder builder, BlockLoader.Docs docs, int offset) throws IOException {
13761390
final int docsCount = docs.count();
@@ -1768,6 +1782,11 @@ public BlockLoader.Builder endPositionEntry() {
17681782
throw new UnsupportedOperationException();
17691783
}
17701784

1785+
@Override
1786+
public void setToDouble(BlockDocValuesReader.ToDouble toDouble) {
1787+
throw new UnsupportedOperationException();
1788+
}
1789+
17711790
@Override
17721791
public void close() {}
17731792
}

server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,12 @@ private static class SingletonDoubles extends BlockDocValuesReader {
398398

399399
@Override
400400
public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boolean nullsFiltered) throws IOException {
401+
if (docValues instanceof BlockLoader.OptionalColumnAtATimeReader direct) {
402+
BlockLoader.Block result = direct.tryReadDoubles(factory, docs, offset, toDouble);
403+
if (result != null) {
404+
return result;
405+
}
406+
}
401407
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
402408
for (int i = offset; i < docs.count(); i++) {
403409
int doc = docs.get(i);

server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ interface OptionalColumnAtATimeReader {
6868
*/
6969
@Nullable
7070
BlockLoader.Block tryRead(BlockFactory factory, Docs docs, int offset) throws IOException;
71+
72+
/**
73+
* Specialization for doubles.
74+
* Returns {@code null} if unable to load values as doubles.
75+
*/
76+
@Nullable
77+
default BlockLoader.Block tryReadDoubles(BlockFactory factory, Docs docs, int offset, BlockDocValuesReader.ToDouble toDouble)
78+
throws IOException {
79+
return null;
80+
}
7181
}
7282

7383
interface RowStrideReader extends Reader {
@@ -537,6 +547,7 @@ interface IntBuilder extends Builder {
537547
* Specialized builder for collecting dense arrays of long values.
538548
*/
539549
interface SingletonLongBuilder extends Builder {
550+
void setToDouble(BlockDocValuesReader.ToDouble toDouble);
540551

541552
SingletonLongBuilder appendLong(long value);
542553

test/framework/src/main/java/org/elasticsearch/index/mapper/TestBlock.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,19 @@ public LongsBuilder appendLong(long value) {
202202
@Override
203203
public BlockLoader.SingletonLongBuilder singletonLongs(int expectedCount) {
204204
final long[] values = new long[expectedCount];
205+
205206
return new BlockLoader.SingletonLongBuilder() {
206207

207208
private int count;
209+
private BlockDocValuesReader.ToDouble toDouble = null;
208210

209211
@Override
210212
public BlockLoader.Block build() {
213+
if (toDouble != null) {
214+
return new TestBlock(
215+
Arrays.stream(values).mapToDouble(toDouble::convert).boxed().collect(Collectors.toUnmodifiableList())
216+
);
217+
}
211218
return new TestBlock(Arrays.stream(values).boxed().collect(Collectors.toUnmodifiableList()));
212219
}
213220

@@ -239,6 +246,11 @@ public BlockLoader.Builder endPositionEntry() {
239246
throw new UnsupportedOperationException();
240247
}
241248

249+
@Override
250+
public void setToDouble(BlockDocValuesReader.ToDouble toDouble) {
251+
this.toDouble = toDouble;
252+
}
253+
242254
@Override
243255
public void close() {}
244256
};

x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/data/DoubleVector.java

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockFactory.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,12 @@ public LongVector newLongArrayVector(long[] values, int positionCount, long preA
322322
return b;
323323
}
324324

325+
public DoubleVector newDoubleOverLongArrayVector(long[] values, BlockUtils.ToDouble toDouble, int positions) {
326+
var v = new DoubleOverLongArrayVector(values, toDouble, positions, this);
327+
adjustBreaker(v.ramBytesUsed());
328+
return v;
329+
}
330+
325331
public final LongBlock newConstantLongBlockWith(long value, int positions) {
326332
return newConstantLongBlockWith(value, positions, 0L);
327333
}

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,14 @@ private static Block constantBlock(BlockFactory blockFactory, ElementType type,
254254
*/
255255
public record Doc(int shard, int segment, int doc) {}
256256

257+
/**
258+
* Functional interface to convert a long value to a double.
259+
*/
260+
@FunctionalInterface
261+
public interface ToDouble {
262+
double convert(long v);
263+
}
264+
257265
/**
258266
* Read all values from a positions into a java object. This is not fast
259267
* but fine to call in the "fold" path.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.compute.data;
9+
10+
// begin generated imports
11+
import org.apache.lucene.util.RamUsageEstimator;
12+
import org.elasticsearch.common.unit.ByteSizeValue;
13+
import org.elasticsearch.core.ReleasableIterator;
14+
15+
import java.util.stream.Collectors;
16+
import java.util.stream.IntStream;
17+
// end generated imports
18+
19+
/**
20+
* Vector implementation that converts long to double values on-the-fly.
21+
*/
22+
final class DoubleOverLongArrayVector extends AbstractVector implements DoubleVector {
23+
24+
static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(DoubleOverLongArrayVector.class)
25+
// TODO: remove these extra bytes once `asBlock` returns a block with a separate reference to the vector.
26+
+ RamUsageEstimator.shallowSizeOfInstance(DoubleVectorBlock.class)
27+
// TODO: remove this if/when we account for memory used by Pages
28+
+ Block.PAGE_MEM_OVERHEAD_PER_BLOCK;
29+
30+
private final long[] values;
31+
private final BlockUtils.ToDouble toDouble;
32+
33+
DoubleOverLongArrayVector(long[] values, BlockUtils.ToDouble toDouble, int positionCount, BlockFactory blockFactory) {
34+
super(positionCount, blockFactory);
35+
this.values = values;
36+
this.toDouble = toDouble;
37+
}
38+
39+
@Override
40+
public DoubleBlock asBlock() {
41+
return new DoubleVectorBlock(this);
42+
}
43+
44+
@Override
45+
public double getDouble(int position) {
46+
return toDouble.convert(values[position]);
47+
}
48+
49+
@Override
50+
public ElementType elementType() {
51+
return ElementType.DOUBLE;
52+
}
53+
54+
@Override
55+
public boolean isConstant() {
56+
return false;
57+
}
58+
59+
@Override
60+
public DoubleVector filter(int... positions) {
61+
try (DoubleVector.Builder builder = blockFactory().newDoubleVectorBuilder(positions.length)) {
62+
for (int pos : positions) {
63+
builder.appendDouble(toDouble.convert((values[pos])));
64+
}
65+
return builder.build();
66+
}
67+
}
68+
69+
@Override
70+
public DoubleBlock keepMask(BooleanVector mask) {
71+
if (getPositionCount() == 0) {
72+
incRef();
73+
return new DoubleVectorBlock(this);
74+
}
75+
if (mask.isConstant()) {
76+
if (mask.getBoolean(0)) {
77+
incRef();
78+
return new DoubleVectorBlock(this);
79+
}
80+
return (DoubleBlock) blockFactory().newConstantNullBlock(getPositionCount());
81+
}
82+
try (DoubleBlock.Builder builder = blockFactory().newDoubleBlockBuilder(getPositionCount())) {
83+
// TODO if X-ArrayBlock used BooleanVector for it's null mask then we could shuffle references here.
84+
for (int p = 0; p < getPositionCount(); p++) {
85+
if (mask.getBoolean(p)) {
86+
builder.appendDouble(getDouble(p));
87+
} else {
88+
builder.appendNull();
89+
}
90+
}
91+
return builder.build();
92+
}
93+
}
94+
95+
@Override
96+
public ReleasableIterator<DoubleBlock> lookup(IntBlock positions, ByteSizeValue targetBlockSize) {
97+
return new DoubleLookup(asBlock(), positions, targetBlockSize);
98+
}
99+
100+
private static long ramBytesEstimated(long[] values) {
101+
return BASE_RAM_BYTES_USED + RamUsageEstimator.sizeOf(values);
102+
}
103+
104+
@Override
105+
public long ramBytesUsed() {
106+
return ramBytesEstimated(values);
107+
}
108+
109+
@Override
110+
public boolean equals(Object obj) {
111+
if (obj instanceof DoubleVector that) {
112+
return DoubleVector.equals(this, that);
113+
}
114+
return false;
115+
}
116+
117+
@Override
118+
public int hashCode() {
119+
return DoubleVector.hash(this);
120+
}
121+
122+
@Override
123+
public String toString() {
124+
String valuesString = IntStream.range(0, getPositionCount())
125+
.limit(10)
126+
.mapToObj(n -> String.valueOf(toDouble.convert(values[n])))
127+
.collect(Collectors.joining(", ", "[", getPositionCount() > 10 ? ", ...]" : "]"));
128+
return getClass().getSimpleName() + "[positions=" + getPositionCount() + ", values=" + valuesString + ']';
129+
}
130+
131+
}

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/X-Vector.java.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public sealed interface $Type$Vector extends Vector permits Constant$Type$Vector
3232
ConstantNullVector {
3333
$elseif(double)$
3434
public sealed interface $Type$Vector extends Vector permits Constant$Type$Vector, $Type$ArrayVector, $Type$BigArrayVector,
35-
ConstantNullVector {
35+
DoubleOverLongArrayVector, ConstantNullVector {
3636
$else$
3737
public sealed interface $Type$Vector extends Vector permits Constant$Type$Vector, $Type$ArrayVector, $Type$BigArrayVector, ConstantNullVector {
3838
$endif$

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/SingletonLongBuilder.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.elasticsearch.compute.data.Block;
1111
import org.elasticsearch.compute.data.BlockFactory;
1212
import org.elasticsearch.core.Releasable;
13+
import org.elasticsearch.index.mapper.BlockDocValuesReader;
1314
import org.elasticsearch.index.mapper.BlockLoader;
1415

1516
/**
@@ -22,6 +23,7 @@ public final class SingletonLongBuilder implements BlockLoader.SingletonLongBuil
2223
private final BlockFactory blockFactory;
2324

2425
private int count;
26+
private BlockDocValuesReader.ToDouble toDouble;
2527

2628
public SingletonLongBuilder(int expectedCount, BlockFactory blockFactory) {
2729
this.blockFactory = blockFactory;
@@ -65,7 +67,10 @@ public long estimatedBytes() {
6567

6668
@Override
6769
public Block build() {
68-
return blockFactory.newLongArrayVector(values, count, 0L).asBlock();
70+
if (toDouble != null) {
71+
return blockFactory.newDoubleOverLongArrayVector(values, toDouble::convert, count).asBlock();
72+
}
73+
return blockFactory.newLongArrayVector(values, count).asBlock();
6974
}
7075

7176
@Override
@@ -81,6 +86,11 @@ public BlockLoader.SingletonLongBuilder appendLongs(long[] values, int from, int
8186
return this;
8287
}
8388

89+
@Override
90+
public void setToDouble(BlockDocValuesReader.ToDouble toDouble) {
91+
this.toDouble = toDouble;
92+
}
93+
8494
@Override
8595
public void close() {
8696
blockFactory.adjustBreaker(-valuesSize(values.length));

0 commit comments

Comments
 (0)