Skip to content

Commit 526b23a

Browse files
committed
Add parsing for InternalBucketMetricValue
1 parent e12339a commit 526b23a

File tree

4 files changed

+169
-3
lines changed

4 files changed

+169
-3
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketmetrics/InternalBucketMetricValue.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.search.aggregations.pipeline.bucketmetrics;
2121

22+
import org.elasticsearch.common.ParseField;
2223
import org.elasticsearch.common.io.stream.StreamInput;
2324
import org.elasticsearch.common.io.stream.StreamOutput;
2425
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -28,11 +29,14 @@
2829
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
2930

3031
import java.io.IOException;
32+
import java.util.Arrays;
3133
import java.util.List;
3234
import java.util.Map;
35+
import java.util.Objects;
3336

3437
public class InternalBucketMetricValue extends InternalNumericMetricsAggregation.SingleValue implements BucketMetricValue {
3538
public static final String NAME = "bucket_metric_value";
39+
static final ParseField KEYS_FIELD = new ParseField("keys");
3640

3741
private double value;
3842
private String[] keys;
@@ -88,7 +92,7 @@ public Object getProperty(List<String> path) {
8892
return this;
8993
} else if (path.size() == 1 && "value".equals(path.get(0))) {
9094
return value();
91-
} else if (path.size() == 1 && "keys".equals(path.get(0))) {
95+
} else if (path.size() == 1 && KEYS_FIELD.getPreferredName().equals(path.get(0))) {
9296
return keys();
9397
} else {
9498
throw new IllegalArgumentException("path not supported for [" + getName() + "]: " + path);
@@ -102,12 +106,23 @@ public XContentBuilder doXContentBody(XContentBuilder builder, Params params) th
102106
if (hasValue && format != DocValueFormat.RAW) {
103107
builder.field(CommonFields.VALUE_AS_STRING.getPreferredName(), format.format(value));
104108
}
105-
builder.startArray("keys");
109+
builder.startArray(KEYS_FIELD.getPreferredName());
106110
for (String key : keys) {
107111
builder.value(key);
108112
}
109113
builder.endArray();
110114
return builder;
111115
}
112116

117+
@Override
118+
protected int doHashCode() {
119+
return Objects.hash(value, Arrays.hashCode(keys));
120+
}
121+
122+
@Override
123+
protected boolean doEquals(Object obj) {
124+
InternalBucketMetricValue other = (InternalBucketMetricValue) obj;
125+
return Objects.equals(value, other.value)
126+
&& Arrays.equals(keys, other.keys);
127+
}
113128
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.pipeline.bucketmetrics;
21+
22+
import org.elasticsearch.common.xcontent.ObjectParser;
23+
import org.elasticsearch.common.xcontent.XContentBuilder;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
import org.elasticsearch.search.aggregations.metrics.ParsedSingleValueNumericMetricsAggregation;
26+
27+
import java.io.IOException;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
31+
public class ParsedBucketMetricValue extends ParsedSingleValueNumericMetricsAggregation implements BucketMetricValue {
32+
33+
private List<String> keys = new ArrayList<>();
34+
35+
@Override
36+
public String[] keys() {
37+
return this.keys.toArray(new String[keys.size()]);
38+
}
39+
40+
@Override
41+
protected String getType() {
42+
return InternalBucketMetricValue.NAME;
43+
}
44+
45+
@Override
46+
protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {
47+
boolean hasValue = !Double.isInfinite(value);
48+
builder.field(CommonFields.VALUE.getPreferredName(), hasValue ? value : null);
49+
if (hasValue && valueAsString != null) {
50+
builder.field(CommonFields.VALUE_AS_STRING.getPreferredName(), valueAsString);
51+
}
52+
builder.startArray(InternalBucketMetricValue.KEYS_FIELD.getPreferredName());
53+
for (String key : keys) {
54+
builder.value(key);
55+
}
56+
builder.endArray();
57+
return builder;
58+
}
59+
60+
private static final ObjectParser<ParsedBucketMetricValue, Void> PARSER = new ObjectParser<>(
61+
ParsedBucketMetricValue.class.getSimpleName(), true, ParsedBucketMetricValue::new);
62+
63+
static {
64+
declareSingleValueFields(PARSER, Double.NEGATIVE_INFINITY);
65+
PARSER.declareStringArray((agg, value) -> agg.keys = value, InternalBucketMetricValue.KEYS_FIELD);
66+
}
67+
68+
public static ParsedBucketMetricValue fromXContent(XContentParser parser, final String name) {
69+
ParsedBucketMetricValue bucketMetricValue = PARSER.apply(parser, null);
70+
bucketMetricValue.setName(name);
71+
return bucketMetricValue;
72+
}
73+
}

core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.elasticsearch.rest.action.search.RestSearchAction;
3434
import org.elasticsearch.script.ScriptService;
3535
import org.elasticsearch.search.DocValueFormat;
36-
import org.elasticsearch.search.DocValueFormat;
3736
import org.elasticsearch.search.SearchModule;
3837
import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder;
3938
import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg;
@@ -54,6 +53,8 @@
5453
import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
5554
import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue;
5655
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
56+
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.InternalBucketMetricValue;
57+
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.ParsedBucketMetricValue;
5758
import org.elasticsearch.search.aggregations.pipeline.derivative.DerivativePipelineAggregationBuilder;
5859
import org.elasticsearch.search.aggregations.pipeline.derivative.ParsedDerivative;
5960
import org.elasticsearch.test.AbstractWireSerializingTestCase;
@@ -91,6 +92,7 @@ static List<NamedXContentRegistry.Entry> getNamedXContents() {
9192
namedXContents.put(ValueCountAggregationBuilder.NAME, (p, c) -> ParsedValueCount.fromXContent(p, (String) c));
9293
namedXContents.put(InternalSimpleValue.NAME, (p, c) -> ParsedSimpleValue.fromXContent(p, (String) c));
9394
namedXContents.put(DerivativePipelineAggregationBuilder.NAME, (p, c) -> ParsedDerivative.fromXContent(p, (String) c));
95+
namedXContents.put(InternalBucketMetricValue.NAME, (p, c) -> ParsedBucketMetricValue.fromXContent(p, (String) c));
9496

9597
return namedXContents.entrySet().stream()
9698
.map(entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue()))
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.pipeline.bucketmetrics;
21+
22+
import org.elasticsearch.common.io.stream.Writeable.Reader;
23+
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
24+
import org.elasticsearch.search.aggregations.ParsedAggregation;
25+
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
26+
27+
import java.util.Collections;
28+
import java.util.List;
29+
import java.util.Map;
30+
31+
public class InternalBucketMetricValueTests extends InternalAggregationTestCase<InternalBucketMetricValue> {
32+
33+
@Override
34+
protected InternalBucketMetricValue createTestInstance(String name, List<PipelineAggregator> pipelineAggregators,
35+
Map<String, Object> metaData) {
36+
double value = frequently() ? randomDoubleBetween(-10000, 100000, true)
37+
: randomFrom(new Double[] { Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN });
38+
String[] keys = new String[randomIntBetween(0, 5)];
39+
for (int i = 0; i < keys.length; i++) {
40+
keys[i] = randomAlphaOfLength(10);
41+
}
42+
return new InternalBucketMetricValue(name, keys, value, randomNumericDocValueFormat(), pipelineAggregators, metaData);
43+
}
44+
45+
@Override
46+
public void testReduceRandom() {
47+
expectThrows(UnsupportedOperationException.class,
48+
() -> createTestInstance("name", Collections.emptyList(), null).reduce(null,
49+
null));
50+
}
51+
52+
@Override
53+
protected void assertReduced(InternalBucketMetricValue reduced, List<InternalBucketMetricValue> inputs) {
54+
// no test since reduce operation is unsupported
55+
}
56+
57+
@Override
58+
protected Reader<InternalBucketMetricValue> instanceReader() {
59+
return InternalBucketMetricValue::new;
60+
}
61+
62+
@Override
63+
protected void assertFromXContent(InternalBucketMetricValue bucketMetricValue, ParsedAggregation parsedAggregation) {
64+
BucketMetricValue parsed = ((BucketMetricValue) parsedAggregation);
65+
assertArrayEquals(bucketMetricValue.keys(), parsed.keys());
66+
if (Double.isInfinite(bucketMetricValue.value()) == false) {
67+
assertEquals(bucketMetricValue.value(), parsed.value(), 0);
68+
assertEquals(bucketMetricValue.getValueAsString(), parsed.getValueAsString());
69+
} else {
70+
// we write Double.NEGATIVE_INFINITY and Double.POSITIVE_INFINITY to xContent as 'null', so we
71+
// cannot differentiate between them. Also we cannot recreate the exact String representation
72+
assertEquals(parsed.value(), Double.NEGATIVE_INFINITY, 0);
73+
}
74+
75+
}
76+
}

0 commit comments

Comments
 (0)