Skip to content

Commit e4fa25a

Browse files
committed
Move serialization logic into block
1 parent 1508be5 commit e4fa25a

File tree

8 files changed

+118
-104
lines changed

8 files changed

+118
-104
lines changed

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

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,39 +92,42 @@ void loadValue(int valueIndex, CompressedExponentialHistogram resultHistogram, B
9292
}
9393
}
9494

95-
/**
96-
* Returns the minimum for the histogram at the given value index.
97-
* @param valueIndex the value index, obtained via {@link #getFirstValueIndex(int)} and {@link #getValueCount(int)}
98-
* @return the minimum, or Double.NaN if the histogram is null or has no values
99-
*/
100-
double getHistogramMin(int valueIndex) {
95+
void serializeValue(int valueIndex, SerializedOutput out, BytesRef tempBytesRef) {
96+
long valueCount = getHistogramValueCount(valueIndex);
97+
out.appendLong(valueCount);
98+
out.appendDouble(getHistogramSum(valueIndex));
99+
out.appendDouble(getHistogramZeroThreshold(valueIndex));
100+
if (valueCount > 0) {
101+
// min / max are only non-null for non-empty histograms
102+
out.appendDouble(getHistogramMin(valueIndex));
103+
out.appendDouble(getHistogramMax(valueIndex));
104+
}
105+
out.appendBytesRef(getEncodedHistogramBytes(valueIndex, tempBytesRef));
106+
}
107+
108+
private double getHistogramMin(int valueIndex) {
101109
int minimaValIndex = minima.getFirstValueIndex(valueIndex);
102110
return minima.isNull(minimaValIndex) ? Double.NaN : minima.getDouble(minimaValIndex);
103111
}
104112

105-
/**
106-
* Returns the maximum for the histogram at the given value index.
107-
* @param valueIndex the value index, obtained via {@link #getFirstValueIndex(int)} and {@link #getValueCount(int)}
108-
* @return the maximum, or Double.NaN if the histogram is null or has no values
109-
*/
110-
double getHistogramMax(int valueIndex) {
113+
private double getHistogramMax(int valueIndex) {
111114
int maximaValIndex = maxima.getFirstValueIndex(valueIndex);
112115
return maxima.isNull(maximaValIndex) ? Double.NaN : maxima.getDouble(maximaValIndex);
113116
}
114117

115-
double getHistogramSum(int valueIndex) {
118+
private double getHistogramSum(int valueIndex) {
116119
return sums.getDouble(sums.getFirstValueIndex(valueIndex));
117120
}
118121

119-
long getHistogramValueCount(int valueIndex) {
122+
private long getHistogramValueCount(int valueIndex) {
120123
return valueCounts.getLong(valueCounts.getFirstValueIndex(valueIndex));
121124
}
122125

123-
double getHistogramZeroThreshold(int valueIndex) {
126+
private double getHistogramZeroThreshold(int valueIndex) {
124127
return zeroThresholds.getDouble(zeroThresholds.getFirstValueIndex(valueIndex));
125128
}
126129

127-
BytesRef getEncodedHistogramBytes(int valueIndex, BytesRef tempBytesRef) {
130+
private BytesRef getEncodedHistogramBytes(int valueIndex, BytesRef tempBytesRef) {
128131
return encodedHistograms.getBytesRef(encodedHistograms.getFirstValueIndex(valueIndex), tempBytesRef);
129132
}
130133

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package org.elasticsearch.compute.data;
99

10+
import org.apache.lucene.util.BytesRef;
1011
import org.elasticsearch.exponentialhistogram.ExponentialHistogram;
1112

1213
/**
@@ -15,6 +16,28 @@
1516
*/
1617
public sealed interface ExponentialHistogramBlock extends Block permits ConstantNullBlock, ExponentialHistogramArrayBlock {
1718

19+
/**
20+
* Abstraction to use for writing individual values via the {@link ExponentialHistogramBlockAccessor#serializeValue(int, SerializedOutput)}.
21+
*/
22+
public interface SerializedOutput {
23+
void appendDouble(double value);
24+
25+
void appendLong(long value);
26+
27+
void appendBytesRef(BytesRef bytesRef);
28+
}
29+
30+
/**
31+
* Abstraction to use for writing individual values via the {@link ExponentialHistogramBlockAccessor#serializeValue(int, SerializedOutput)}.
32+
*/
33+
public interface SerializedInput {
34+
double readDouble();
35+
36+
long readLong();
37+
38+
BytesRef readBytesRef(BytesRef tempBytesRef);
39+
}
40+
1841
static boolean equals(ExponentialHistogramBlock blockA, ExponentialHistogramBlock blockB) {
1942
if (blockA == blockB) {
2043
return true;

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

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -47,52 +47,20 @@ public ExponentialHistogram get(int valueIndex) {
4747
return reusedHistogram;
4848
}
4949

50-
public double getSum(int valueIndex) {
51-
assert block.isNull(valueIndex) == false;
52-
assert block.isReleased() == false;
53-
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
54-
return arrayBlock.getHistogramSum(valueIndex);
55-
}
56-
57-
public long getValueCount(int valueIndex) {
58-
assert block.isNull(valueIndex) == false;
59-
assert block.isReleased() == false;
60-
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
61-
return arrayBlock.getHistogramValueCount(valueIndex);
62-
}
63-
64-
public double getMin(int valueIndex) {
65-
assert block.isNull(valueIndex) == false;
66-
assert block.isReleased() == false;
67-
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
68-
return arrayBlock.getHistogramMin(valueIndex);
69-
}
70-
71-
public double getMax(int valueIndex) {
72-
assert block.isNull(valueIndex) == false;
73-
assert block.isReleased() == false;
74-
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
75-
return arrayBlock.getHistogramMax(valueIndex);
76-
}
77-
78-
public double getZeroThreshold(int valueIndex) {
79-
assert block.isNull(valueIndex) == false;
80-
assert block.isReleased() == false;
81-
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
82-
return arrayBlock.getHistogramZeroThreshold(valueIndex);
83-
}
84-
85-
public BytesRef getEncodedHistogramBytes(int valueIndex) {
50+
/**
51+
* Encodes and appends a histogram value, so that it can be later deserialized
52+
* via {@link ExponentialHistogramBlockBuilder#deserializeAndAppend(ExponentialHistogramBlock.SerializedInput)}.
53+
*
54+
* @param output the output to deserialize into
55+
*/
56+
public void serializeValue(int valueIndex, ExponentialHistogramBlock.SerializedOutput output) {
8657
assert block.isNull(valueIndex) == false;
8758
assert block.isReleased() == false;
8859
ExponentialHistogramArrayBlock arrayBlock = (ExponentialHistogramArrayBlock) block;
8960
if (tempBytesRef == null) {
9061
tempBytesRef = new BytesRef();
9162
}
92-
arrayBlock.getEncodedHistogramBytes(valueIndex, tempBytesRef);
93-
return tempBytesRef;
63+
arrayBlock.serializeValue(valueIndex, output, tempBytesRef);
9464
}
9565

96-
97-
9866
}

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public class ExponentialHistogramBlockBuilder implements Block.Builder {
2525
private final DoubleBlock.Builder zeroThresholdsBuilder;
2626
private final BytesRefBlock.Builder encodedHistogramsBuilder;
2727

28+
private final BytesRef scratch = new BytesRef();
29+
2830
ExponentialHistogramBlockBuilder(int estimatedSize, BlockFactory blockFactory) {
2931
DoubleBlock.Builder minimaBuilder = null;
3032
DoubleBlock.Builder maximaBuilder = null;
@@ -101,23 +103,25 @@ public ExponentialHistogramBlockBuilder append(ExponentialHistogram histogram) {
101103
return this;
102104
}
103105

104-
public ExponentialHistogramBlockBuilder appendEncoded(double sum, long valueCount, double min, double max, double zeroThreshold, BytesRef encodedHistogram) {
105-
sumsBuilder.appendDouble(sum);
106+
/**
107+
* Decodes and appends a value serialized with
108+
* {@link ExponentialHistogramBlockAccessor#serializeValue(int, ExponentialHistogramBlock.SerializedOutput)}.
109+
*
110+
* @param input the input to deserialize from
111+
*/
112+
public void deserializeAndAppend(ExponentialHistogramBlock.SerializedInput input) {
113+
long valueCount = input.readLong();
106114
valueCountsBuilder.appendLong(valueCount);
107-
zeroThresholdsBuilder.appendDouble(zeroThreshold);
108-
encodedHistogramsBuilder.appendBytesRef(encodedHistogram);
109-
if (valueCount == 0) {
110-
assert Double.isNaN(min) : "min should be NaN for empty histogram";
111-
assert Double.isNaN(max) : "max should be NaN for empty histogram";
115+
sumsBuilder.appendDouble(input.readDouble());
116+
zeroThresholdsBuilder.appendDouble(input.readDouble());
117+
if (valueCount > 0) {
118+
minimaBuilder.appendDouble(input.readDouble());
119+
maximaBuilder.appendDouble(input.readDouble());
120+
} else {
112121
minimaBuilder.appendNull();
113122
maximaBuilder.appendNull();
114-
} else {
115-
assert Double.isNaN(min) == false : "min should be non-NaN for non-empty histogram";
116-
assert Double.isNaN(max) == false : "max should be non-NaN for non-empty histogram";
117-
minimaBuilder.appendDouble(min);
118-
maximaBuilder.appendDouble(max);
119123
}
120-
return this;
124+
encodedHistogramsBuilder.appendBytesRef(input.readBytesRef(scratch));
121125
}
122126

123127
@Override

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static ResultBuilder resultBuilderFor(
5555
case NULL -> new ResultBuilderForNull(blockFactory);
5656
case DOC -> new ResultBuilderForDoc(blockFactory, (DocVectorEncoder) encoder, positions);
5757
case AGGREGATE_METRIC_DOUBLE -> new ResultBuilderForAggregateMetricDouble(blockFactory, positions);
58-
case EXPONENTIAL_HISTOGRAM -> new ResultBuilderForExponentialHistogram(blockFactory, positions);
58+
case EXPONENTIAL_HISTOGRAM -> new ResultBuilderForExponentialHistogram(blockFactory, positions);
5959
default -> {
6060
assert false : "Result builder for [" + elementType + "]";
6161
throw new UnsupportedOperationException("Result builder for [" + elementType + "]");

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilderForExponentialHistogram.java

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,23 @@
88
package org.elasticsearch.compute.operator.topn;
99

1010
import org.apache.lucene.util.BytesRef;
11-
import org.elasticsearch.compute.data.AggregateMetricDoubleBlockBuilder;
1211
import org.elasticsearch.compute.data.Block;
1312
import org.elasticsearch.compute.data.BlockFactory;
13+
import org.elasticsearch.compute.data.ExponentialHistogramBlock;
1414
import org.elasticsearch.compute.data.ExponentialHistogramBlockBuilder;
15-
import org.elasticsearch.index.mapper.BlockLoader;
16-
17-
import java.util.List;
1815

1916
public class ResultBuilderForExponentialHistogram implements ResultBuilder {
2017

2118
private final ExponentialHistogramBlockBuilder builder;
22-
private final BytesRef scratch = new BytesRef();
19+
private final ReusableTopNEncoderInput reusableInput = new ReusableTopNEncoderInput();
2320

2421
ResultBuilderForExponentialHistogram(BlockFactory blockFactory, int positions) {
2522
this.builder = blockFactory.newExponentialHistogramBlockBuilder(positions);
2623
}
2724

2825
@Override
2926
public void decodeKey(BytesRef keys) {
30-
throw new AssertionError("AggregateMetricDoubleBlock can't be a key");
27+
throw new AssertionError("ExponentialHistogramBlock can't be a key");
3128
}
3229

3330
@Override
@@ -37,21 +34,9 @@ public void decodeValue(BytesRef values) {
3734
builder.appendNull();
3835
return;
3936
}
40-
assert count == 1: "ExponentialHistogramBlock does not support multi values";
41-
long histogramValueCount = TopNEncoder.DEFAULT_UNSORTABLE.decodeLong(values);
42-
double sum = TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(values);
43-
double min = TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(values);
44-
double max = TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(values);
45-
double zeroThreshold = TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(values);
46-
BytesRef encodedHistogramBytes = TopNEncoder.DEFAULT_UNSORTABLE.decodeBytesRef(values, scratch);
47-
builder.appendEncoded(
48-
sum,
49-
histogramValueCount,
50-
min,
51-
max,
52-
zeroThreshold,
53-
encodedHistogramBytes
54-
);
37+
assert count == 1 : "ExponentialHistogramBlock does not support multi values";
38+
reusableInput.inputValues = values;
39+
builder.deserializeAndAppend(reusableInput);
5540
}
5641

5742
@Override
@@ -68,4 +53,23 @@ public String toString() {
6853
public void close() {
6954
builder.close();
7055
}
56+
57+
private class ReusableTopNEncoderInput implements ExponentialHistogramBlock.SerializedInput {
58+
BytesRef inputValues;
59+
60+
@Override
61+
public double readDouble() {
62+
return TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(inputValues);
63+
}
64+
65+
@Override
66+
public long readLong() {
67+
return TopNEncoder.DEFAULT_UNSORTABLE.decodeLong(inputValues);
68+
}
69+
70+
@Override
71+
public BytesRef readBytesRef(BytesRef tempBytesRef) {
72+
return TopNEncoder.DEFAULT_UNSORTABLE.decodeBytesRef(inputValues, tempBytesRef);
73+
}
74+
}
7175
}

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static ValueExtractor extractorFor(ElementType elementType, TopNEncoder encoder,
5454
case NULL -> new ValueExtractorForNull();
5555
case DOC -> new ValueExtractorForDoc(encoder, ((DocBlock) block).asVector());
5656
case AGGREGATE_METRIC_DOUBLE -> new ValueExtractorForAggregateMetricDouble(encoder, (AggregateMetricDoubleBlock) block);
57-
case EXPONENTIAL_HISTOGRAM -> new ValueExtractorForExponentialHistogram(encoder, (ExponentialHistogramBlock) block);
57+
case EXPONENTIAL_HISTOGRAM -> new ValueExtractorForExponentialHistogram(encoder, (ExponentialHistogramBlock) block);
5858
default -> {
5959
assert false : "No value extractor for [" + block.elementType() + "]";
6060
throw new UnsupportedOperationException("No value extractor for [" + block.elementType() + "]");

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractorForExponentialHistogram.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,15 @@
77

88
package org.elasticsearch.compute.operator.topn;
99

10-
import org.elasticsearch.compute.data.AggregateMetricDoubleBlock;
11-
import org.elasticsearch.compute.data.DoubleBlock;
10+
import org.apache.lucene.util.BytesRef;
1211
import org.elasticsearch.compute.data.ExponentialHistogramBlock;
1312
import org.elasticsearch.compute.data.ExponentialHistogramBlockAccessor;
14-
import org.elasticsearch.compute.data.IntBlock;
1513
import org.elasticsearch.compute.operator.BreakingBytesRefBuilder;
1614

17-
import java.util.List;
18-
1915
public class ValueExtractorForExponentialHistogram implements ValueExtractor {
2016
private final ExponentialHistogramBlock block;
2117
private final ExponentialHistogramBlockAccessor accessor;
18+
private final ReusableTopNEncoderOutput reusableOutput = new ReusableTopNEncoderOutput();
2219

2320
ValueExtractorForExponentialHistogram(TopNEncoder encoder, ExponentialHistogramBlock block) {
2421
assert encoder == TopNEncoder.DEFAULT_UNSORTABLE;
@@ -32,20 +29,35 @@ public void writeValue(BreakingBytesRefBuilder values, int position) {
3229
if (block.isNull(position)) {
3330
TopNEncoder.DEFAULT_UNSORTABLE.encodeVInt(0, values);
3431
} else {
35-
assert block.getValueCount(position) == 1: "Multi-valued ExponentialHistogram not supported in TopN";
32+
assert block.getValueCount(position) == 1 : "Multi-valued ExponentialHistogram blcoks are not supported in TopN";
3633
TopNEncoder.DEFAULT_UNSORTABLE.encodeVInt(1, values);
3734
int valueIndex = block.getFirstValueIndex(position);
38-
TopNEncoder.DEFAULT_UNSORTABLE.encodeLong(accessor.getValueCount(valueIndex), values);
39-
TopNEncoder.DEFAULT_UNSORTABLE.encodeDouble(accessor.getSum(valueIndex), values);
40-
TopNEncoder.DEFAULT_UNSORTABLE.encodeDouble(accessor.getMin(valueIndex), values);
41-
TopNEncoder.DEFAULT_UNSORTABLE.encodeDouble(accessor.getMax(valueIndex), values);
42-
TopNEncoder.DEFAULT_UNSORTABLE.encodeDouble(accessor.getZeroThreshold(valueIndex), values);
43-
TopNEncoder.DEFAULT_UNSORTABLE.encodeBytesRef(accessor.getEncodedHistogramBytes(valueIndex), values);
35+
reusableOutput.target = values;
36+
accessor.serializeValue(valueIndex, reusableOutput);
4437
}
4538
}
4639

4740
@Override
4841
public String toString() {
4942
return "ValueExtractorForExponentialHistogram";
5043
}
44+
45+
private static final class ReusableTopNEncoderOutput implements ExponentialHistogramBlock.SerializedOutput {
46+
BreakingBytesRefBuilder target;
47+
48+
@Override
49+
public void appendDouble(double value) {
50+
TopNEncoder.DEFAULT_UNSORTABLE.encodeDouble(value, target);
51+
}
52+
53+
@Override
54+
public void appendLong(long value) {
55+
TopNEncoder.DEFAULT_UNSORTABLE.encodeLong(value, target);
56+
}
57+
58+
@Override
59+
public void appendBytesRef(BytesRef value) {
60+
TopNEncoder.DEFAULT_UNSORTABLE.encodeBytesRef(value, target);
61+
}
62+
}
5163
}

0 commit comments

Comments
 (0)