From a6c38b8f8a9c95f81c10bd97318d9ab66142108e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Fri, 28 Apr 2017 12:10:16 +0200 Subject: [PATCH] Add parsing for InternalGeoBounds (#24365) --- .../metrics/geobounds/InternalGeoBounds.java | 23 ++-- .../metrics/geobounds/ParsedGeoBounds.java | 105 ++++++++++++++++++ .../InternalAggregationTestCase.java | 6 +- .../geobounds/InternalGeoBoundsTests.java | 34 ++++-- 4 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/ParsedGeoBounds.java diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBounds.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBounds.java index 2a3d03e43e6..37297475a28 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBounds.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBounds.java @@ -19,6 +19,7 @@ package org.elasticsearch.search.aggregations.metrics.geobounds; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -32,6 +33,14 @@ import java.util.Map; import java.util.Objects; public class InternalGeoBounds extends InternalAggregation implements GeoBounds { + + final static ParseField BOUNDS_FIELD = new ParseField("bounds"); + final static ParseField TOP_LEFT_FIELD = new ParseField("top_left"); + final static ParseField BOTTOM_RIGHT_FIELD = new ParseField("bottom_right"); + final static ParseField LAT_FIELD = new ParseField("lat"); + final static ParseField LON_FIELD = new ParseField("lon"); + + final double top; final double bottom; final double posLeft; @@ -170,14 +179,14 @@ public class InternalGeoBounds extends InternalAggregation implements GeoBounds GeoPoint topLeft = topLeft(); GeoPoint bottomRight = bottomRight(); if (topLeft != null) { - builder.startObject("bounds"); - builder.startObject("top_left"); - builder.field("lat", topLeft.lat()); - builder.field("lon", topLeft.lon()); + builder.startObject(BOUNDS_FIELD.getPreferredName()); + builder.startObject(TOP_LEFT_FIELD.getPreferredName()); + builder.field(LAT_FIELD.getPreferredName(), topLeft.lat()); + builder.field(LON_FIELD.getPreferredName(), topLeft.lon()); builder.endObject(); - builder.startObject("bottom_right"); - builder.field("lat", bottomRight.lat()); - builder.field("lon", bottomRight.lon()); + builder.startObject(BOTTOM_RIGHT_FIELD.getPreferredName()); + builder.field(LAT_FIELD.getPreferredName(), bottomRight.lat()); + builder.field(LON_FIELD.getPreferredName(), bottomRight.lon()); builder.endObject(); builder.endObject(); } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/ParsedGeoBounds.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/ParsedGeoBounds.java new file mode 100644 index 00000000000..04d2b2448d2 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/geobounds/ParsedGeoBounds.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.geobounds; + +import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.aggregations.ParsedAggregation; + +import java.io.IOException; + +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBounds.BOTTOM_RIGHT_FIELD; +import static org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBounds.BOUNDS_FIELD; +import static org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBounds.LAT_FIELD; +import static org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBounds.LON_FIELD; +import static org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBounds.TOP_LEFT_FIELD; + +public class ParsedGeoBounds extends ParsedAggregation implements GeoBounds { + private GeoPoint topLeft; + private GeoPoint bottomRight; + + @Override + public String getType() { + return GeoBoundsAggregationBuilder.NAME; + } + + @Override + public XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException { + if (topLeft != null) { + builder.startObject("bounds"); + builder.startObject("top_left"); + builder.field("lat", topLeft.getLat()); + builder.field("lon", topLeft.getLon()); + builder.endObject(); + builder.startObject("bottom_right"); + builder.field("lat", bottomRight.getLat()); + builder.field("lon", bottomRight.getLon()); + builder.endObject(); + builder.endObject(); + } + return builder; + } + + @Override + public GeoPoint topLeft() { + return topLeft; + } + + @Override + public GeoPoint bottomRight() { + return bottomRight; + } + + private static final ObjectParser PARSER = new ObjectParser<>(ParsedGeoBounds.class.getSimpleName(), true, + ParsedGeoBounds::new); + + private static final ConstructingObjectParser, Void> BOUNDS_PARSER = + new ConstructingObjectParser<>(ParsedGeoBounds.class.getSimpleName() + "_BOUNDS", true, + args -> new Tuple<>((GeoPoint) args[0], (GeoPoint) args[1])); + + private static final ObjectParser GEO_POINT_PARSER = new ObjectParser<>( + ParsedGeoBounds.class.getSimpleName() + "_POINT", true, GeoPoint::new); + + static { + declareAggregationFields(PARSER); + PARSER.declareObject((agg, bbox) -> { + agg.topLeft = bbox.v1(); + agg.bottomRight = bbox.v2(); + }, BOUNDS_PARSER, BOUNDS_FIELD); + + BOUNDS_PARSER.declareObject(constructorArg(), GEO_POINT_PARSER, TOP_LEFT_FIELD); + BOUNDS_PARSER.declareObject(constructorArg(), GEO_POINT_PARSER, BOTTOM_RIGHT_FIELD); + + GEO_POINT_PARSER.declareDouble(GeoPoint::resetLat, LAT_FIELD); + GEO_POINT_PARSER.declareDouble(GeoPoint::resetLon, LON_FIELD); + } + + public static ParsedGeoBounds fromXContent(XContentParser parser, final String name) { + ParsedGeoBounds geoBounds = PARSER.apply(parser, null); + geoBounds.setName(name); + return geoBounds; + } + +} diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java index d4c293a0e8b..664a2b756df 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java @@ -38,6 +38,8 @@ import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg; import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.cardinality.ParsedCardinality; +import org.elasticsearch.search.aggregations.metrics.geobounds.GeoBoundsAggregationBuilder; +import org.elasticsearch.search.aggregations.metrics.geobounds.ParsedGeoBounds; import org.elasticsearch.search.aggregations.metrics.max.MaxAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.max.ParsedMax; import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder; @@ -113,7 +115,9 @@ public abstract class InternalAggregationTestCase namedXContents.put(StatsAggregationBuilder.NAME, (p, c) -> ParsedStats.fromXContent(p, (String) c)); namedXContents.put(StatsBucketPipelineAggregationBuilder.NAME, (p, c) -> ParsedStatsBucket.fromXContent(p, (String) c)); namedXContents.put(ExtendedStatsAggregationBuilder.NAME, (p, c) -> ParsedExtendedStats.fromXContent(p, (String) c)); - namedXContents.put(ExtendedStatsBucketPipelineAggregationBuilder.NAME, (p, c) -> ParsedExtendedStatsBucket.fromXContent(p, (String) c)); + namedXContents.put(ExtendedStatsBucketPipelineAggregationBuilder.NAME, + (p, c) -> ParsedExtendedStatsBucket.fromXContent(p, (String) c)); + namedXContents.put(GeoBoundsAggregationBuilder.NAME, (p, c) -> ParsedGeoBounds.fromXContent(p, (String) c)); return namedXContents.entrySet().stream() .map(entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue())) diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBoundsTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBoundsTests.java index cd5d4d43d17..611178d1bf2 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBoundsTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/geobounds/InternalGeoBoundsTests.java @@ -21,6 +21,7 @@ package org.elasticsearch.search.aggregations.metrics.geobounds; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.search.aggregations.InternalAggregationTestCase; +import org.elasticsearch.search.aggregations.ParsedAggregation; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.Collections; @@ -35,8 +36,10 @@ public class InternalGeoBoundsTests extends InternalAggregationTestCase pipelineAggregators, Map metaData) { + // we occasionally want to test top = Double.NEGATIVE_INFINITY since this triggers empty xContent object + double top = frequently() ? randomDouble() : Double.NEGATIVE_INFINITY; InternalGeoBounds geo = new InternalGeoBounds(name, - randomDouble(), randomDouble(), randomDouble(), randomDouble(), + top, randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomBoolean(), pipelineAggregators, Collections.emptyMap()); return geo; @@ -70,12 +73,29 @@ public class InternalGeoBoundsTests extends InternalAggregationTestCase