Skip to content

Commit e625bb4

Browse files
committed
Create deserialization utility in exp histo lib
1 parent af6efdb commit e625bb4

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

libs/exponential-histogram/src/main/java/org/elasticsearch/exponentialhistogram/ExponentialHistogramXContent.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121

2222
package org.elasticsearch.exponentialhistogram;
2323

24+
import org.elasticsearch.core.Types;
2425
import org.elasticsearch.xcontent.XContentBuilder;
26+
import org.elasticsearch.xcontent.XContentParser;
2527

2628
import java.io.IOException;
29+
import java.util.Collections;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.function.BiConsumer;
2733

2834
/**
2935
* Handles the serialization of an {@link ExponentialHistogram} to XContent.
@@ -101,4 +107,54 @@ private static void writeBuckets(XContentBuilder b, String fieldName, Exponentia
101107
b.endObject();
102108
}
103109

110+
/**
111+
* Parses an {@link ExponentialHistogram} from the provided {@link XContentParser}.
112+
* This method is neither optimized, nor does it do any validation of the parsed content.
113+
* No estimation for missing sum/min/max is done.
114+
* Therefore only intended for testing!
115+
*
116+
* @param xContent the serialized histogram to read
117+
* @return the deserialized histogram
118+
* @throws IOException if the XContentParser throws an IOException
119+
*/
120+
public static ExponentialHistogram parseForTesting(XContentParser xContent) throws IOException {
121+
return parseForTesting(xContent.map());
122+
}
123+
124+
/**
125+
* Parses an {@link ExponentialHistogram} from a {@link Map}.
126+
* This method is neither optimized, nor does it do any validation of the parsed content.
127+
* No estimation for missing sum/min/max is done.
128+
* Therefore only intended for testing!
129+
*
130+
* @param xContent the serialized histogram as a map
131+
* @return the deserialized histogram
132+
*/
133+
public static ExponentialHistogram parseForTesting(Map<String, Object> xContent) {
134+
int scale = ((Number) xContent.get(SCALE_FIELD)).intValue();
135+
ExponentialHistogramBuilder builder = ExponentialHistogram.builder(scale, ExponentialHistogramCircuitBreaker.noop());
136+
137+
Map<String, Number> zero = Types.forciblyCast(xContent.getOrDefault(ZERO_FIELD, Collections.emptyMap()));
138+
double zeroThreshold = zero.getOrDefault(ZERO_THRESHOLD_FIELD, 0).doubleValue();
139+
long zeroCount = zero.getOrDefault(ZERO_COUNT_FIELD, 0).longValue();
140+
builder.zeroBucket(ZeroBucket.create(zeroThreshold, zeroCount));
141+
142+
builder.sum(((Number) xContent.getOrDefault(SUM_FIELD, 0)).doubleValue());
143+
builder.min(((Number) xContent.getOrDefault(MIN_FIELD, Double.NaN)).doubleValue());
144+
builder.max(((Number) xContent.getOrDefault(MAX_FIELD, Double.NaN)).doubleValue());
145+
146+
parseBuckets(Types.forciblyCast(xContent.getOrDefault(NEGATIVE_FIELD, Collections.emptyMap())), builder::setNegativeBucket);
147+
parseBuckets(Types.forciblyCast(xContent.getOrDefault(POSITIVE_FIELD, Collections.emptyMap())), builder::setPositiveBucket);
148+
149+
return builder.build();
150+
}
151+
152+
private static void parseBuckets(Map<String, List<Number>> serializedBuckets, BiConsumer<Long, Long> bucketSetter) {
153+
List<Number> indices = serializedBuckets.getOrDefault(BUCKET_INDICES_FIELD, Collections.emptyList());
154+
List<Number> counts = serializedBuckets.getOrDefault(BUCKET_COUNTS_FIELD, Collections.emptyList());
155+
assert indices.size() == counts.size();
156+
for (int i = 0; i < indices.size(); i++) {
157+
bucketSetter.accept(indices.get(i).longValue(), counts.get(i).longValue());
158+
}
159+
}
104160
}

libs/exponential-histogram/src/test/java/org/elasticsearch/exponentialhistogram/ExponentialHistogramXContentTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
import org.elasticsearch.common.Strings;
2525
import org.elasticsearch.xcontent.XContentBuilder;
26+
import org.elasticsearch.xcontent.XContentParser;
27+
import org.elasticsearch.xcontent.XContentParserConfiguration;
2628
import org.elasticsearch.xcontent.json.JsonXContent;
2729

2830
import java.io.IOException;
@@ -62,18 +64,21 @@ public void testFullHistogram() {
6264
+ "}"
6365
)
6466
);
67+
checkRoundTrip(histo);
6568
}
6669

6770
public void testOnlyZeroThreshold() {
6871
ExponentialHistogram histo = createAutoReleasedHistogram(b -> b.scale(3).sum(1.1).zeroBucket(ZeroBucket.create(5.0, 0)));
6972
assertThat(toJson(histo), equalTo("{\"scale\":3,\"sum\":1.1,\"zero\":{\"threshold\":5.0}}"));
73+
checkRoundTrip(histo);
7074
}
7175

7276
public void testOnlyZeroCount() {
7377
ExponentialHistogram histo = createAutoReleasedHistogram(
7478
b -> b.zeroBucket(ZeroBucket.create(0.0, 7)).scale(2).sum(1.1).min(0).max(0)
7579
);
7680
assertThat(toJson(histo), equalTo("{\"scale\":2,\"sum\":1.1,\"min\":0.0,\"max\":0.0,\"zero\":{\"count\":7}}"));
81+
checkRoundTrip(histo);
7782
}
7883

7984
public void testOnlyPositiveBuckets() {
@@ -84,6 +89,7 @@ public void testOnlyPositiveBuckets() {
8489
toJson(histo),
8590
equalTo("{\"scale\":4,\"sum\":1.1,\"min\":0.5,\"max\":2.5,\"positive\":{\"indices\":[-1,2],\"counts\":[3,5]}}")
8691
);
92+
checkRoundTrip(histo);
8793
}
8894

8995
public void testOnlyNegativeBuckets() {
@@ -94,6 +100,7 @@ public void testOnlyNegativeBuckets() {
94100
toJson(histo),
95101
equalTo("{\"scale\":5,\"sum\":1.1,\"min\":-0.5,\"max\":-0.25,\"negative\":{\"indices\":[-1,2],\"counts\":[4,6]}}")
96102
);
103+
checkRoundTrip(histo);
97104
}
98105

99106
private static String toJson(ExponentialHistogram histo) {
@@ -105,4 +112,17 @@ private static String toJson(ExponentialHistogram histo) {
105112
}
106113
}
107114

115+
private static void checkRoundTrip(ExponentialHistogram histo) {
116+
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
117+
ExponentialHistogramXContent.serialize(builder, histo);
118+
String json = Strings.toString(builder);
119+
try (XContentParser parser = JsonXContent.jsonXContent.createParser(XContentParserConfiguration.EMPTY, json)) {
120+
ExponentialHistogram parsed = ExponentialHistogramXContent.parseForTesting(parser);
121+
assertThat(parsed, equalTo(histo));
122+
}
123+
} catch (IOException e) {
124+
throw new RuntimeException(e);
125+
}
126+
}
127+
108128
}

0 commit comments

Comments
 (0)