Skip to content

Commit 56162a9

Browse files
authoredSep 19, 2022
Add GeoBounds aggregation on GeoShape field type.(#3980) (#4266)
Enables geo_bounds aggregation to work with geo_shape field types. This enhancement includes: * Addition of Doc values on the GeoShape Field. * Addition of GeoShape ValueSource level code interfaces for accessing the DocValues. * Addition of Missing Value feature in the GeoShape Aggregations. Signed-off-by: Navneet Verma <navneev@amazon.com>
1 parent fa07cd9 commit 56162a9

31 files changed

+2369
-64
lines changed
 

‎CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
8080
- Github workflow for changelog verification ([#4085](https://github.com/opensearch-project/OpenSearch/pull/4085))
8181
- Label configuration for dependabot PRs ([#4348](https://github.com/opensearch-project/OpenSearch/pull/4348))
8282
- Added RestLayer Changes for PIT stats ([#4217](https://github.com/opensearch-project/OpenSearch/pull/4217))
83+
- Added GeoBounds aggregation on GeoShape field type.([#4266](https://github.com/opensearch-project/OpenSearch/pull/4266))
84+
- Addition of Doc values on the GeoShape Field
85+
- Addition of GeoShape ValueSource level code interfaces for accessing the DocValues.
86+
- Addition of Missing Value feature in the GeoShape Aggregations.
8387

8488
### Changed
8589

‎libs/geo/src/main/java/org/opensearch/geometry/GeometryCollection.java

+9
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ public G get(int i) {
8888
return shapes.get(i);
8989
}
9090

91+
/**
92+
* Returns a {@link List} of All {@link Geometry} present in this collection.
93+
*
94+
* @return a {@link List} of All {@link Geometry}
95+
*/
96+
public List<G> getAll() {
97+
return shapes;
98+
}
99+
91100
@Override
92101
public boolean equals(Object o) {
93102
if (this == o) return true;

‎modules/geo/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ restResources {
4040
includeCore '_common', 'indices', 'index', 'search', 'bulk'
4141
}
4242
}
43+
4344
artifacts {
4445
restTests(project.file('src/yamlRestTest/resources/rest-api-spec/test'))
4546
}

‎modules/geo/src/internalClusterTest/java/org/opensearch/geo/GeoModulePluginIntegTestCase.java

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
* for the test cluster on which integration tests are running.
2222
*/
2323
public abstract class GeoModulePluginIntegTestCase extends OpenSearchIntegTestCase {
24+
25+
protected static final double GEOHASH_TOLERANCE = 1E-5D;
26+
2427
/**
2528
* Returns a collection of plugins that should be loaded on each node for doing the integration tests. As this
2629
* geo plugin is not getting packaged in a zip, we need to load it before the tests run.

‎modules/geo/src/internalClusterTest/java/org/opensearch/geo/search/MissingValueIT.java

+115-18
Original file line numberDiff line numberDiff line change
@@ -8,52 +8,149 @@
88

99
package org.opensearch.geo.search;
1010

11+
import org.hamcrest.MatcherAssert;
12+
import org.junit.Before;
1113
import org.opensearch.action.search.SearchResponse;
14+
import org.opensearch.common.geo.GeoPoint;
1215
import org.opensearch.geo.GeoModulePluginIntegTestCase;
16+
import org.opensearch.geo.search.aggregations.common.GeoBoundsHelper;
1317
import org.opensearch.geo.search.aggregations.metrics.GeoBounds;
1418
import org.opensearch.geo.tests.common.AggregationBuilders;
19+
import org.opensearch.geo.tests.common.RandomGeoGenerator;
20+
import org.opensearch.geo.tests.common.RandomGeoGeometryGenerator;
21+
import org.opensearch.geometry.Geometry;
22+
import org.opensearch.geometry.utils.WellKnownText;
1523
import org.opensearch.test.OpenSearchIntegTestCase;
1624

1725
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertAcked;
1826
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertSearchResponse;
1927
import static org.hamcrest.Matchers.closeTo;
2028

29+
/**
30+
* Tests to validate if user specified a missingValue in the input while doing the aggregation
31+
*/
2132
@OpenSearchIntegTestCase.SuiteScopeTestCase
2233
public class MissingValueIT extends GeoModulePluginIntegTestCase {
2334

35+
private static final String INDEX_NAME = "idx";
36+
private static final String GEO_SHAPE_FIELD_NAME = "myshape";
37+
private static final String GEO_SHAPE_FIELD_TYPE = "type=geo_shape";
38+
private static final String AGGREGATION_NAME = "bounds";
39+
private static final String NON_EXISTENT_FIELD = "non_existing_field";
40+
private static final WellKnownText WKT = WellKnownText.INSTANCE;
41+
private static Geometry indexedGeometry;
42+
private static GeoPoint indexedGeoPoint;
43+
private GeoPoint bottomRight;
44+
private GeoPoint topLeft;
45+
2446
@Override
2547
protected void setupSuiteScopeCluster() throws Exception {
26-
assertAcked(prepareCreate("idx").setMapping("date", "type=date", "location", "type=geo_point", "str", "type=keyword").get());
48+
assertAcked(
49+
prepareCreate(INDEX_NAME).setMapping(
50+
"date",
51+
"type=date",
52+
"location",
53+
"type=geo_point",
54+
"str",
55+
"type=keyword",
56+
GEO_SHAPE_FIELD_NAME,
57+
GEO_SHAPE_FIELD_TYPE
58+
).get()
59+
);
60+
indexedGeometry = RandomGeoGeometryGenerator.randomGeometry(random());
61+
indexedGeoPoint = RandomGeoGenerator.randomPoint(random());
62+
assert indexedGeometry != null;
2763
indexRandom(
2864
true,
29-
client().prepareIndex("idx").setId("1").setSource(),
30-
client().prepareIndex("idx")
65+
client().prepareIndex(INDEX_NAME).setId("1").setSource(),
66+
client().prepareIndex(INDEX_NAME)
3167
.setId("2")
32-
.setSource("str", "foo", "long", 3L, "double", 5.5, "date", "2015-05-07", "location", "1,2")
68+
.setSource(
69+
"str",
70+
"foo",
71+
"long",
72+
3L,
73+
"double",
74+
5.5,
75+
"date",
76+
"2015-05-07",
77+
"location",
78+
indexedGeoPoint.toString(),
79+
GEO_SHAPE_FIELD_NAME,
80+
WKT.toWKT(indexedGeometry)
81+
)
3382
);
3483
}
3584

85+
@Before
86+
public void runBeforeEachTest() {
87+
bottomRight = new GeoPoint(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
88+
topLeft = new GeoPoint(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
89+
}
90+
3691
public void testUnmappedGeoBounds() {
37-
SearchResponse response = client().prepareSearch("idx")
38-
.addAggregation(AggregationBuilders.geoBounds("bounds").field("non_existing_field").missing("2,1"))
92+
final GeoPoint missingGeoPoint = RandomGeoGenerator.randomPoint(random());
93+
GeoBoundsHelper.updateBoundsBottomRight(missingGeoPoint, bottomRight);
94+
GeoBoundsHelper.updateBoundsTopLeft(missingGeoPoint, topLeft);
95+
SearchResponse response = client().prepareSearch(INDEX_NAME)
96+
.addAggregation(
97+
AggregationBuilders.geoBounds(AGGREGATION_NAME)
98+
.field(NON_EXISTENT_FIELD)
99+
.wrapLongitude(false)
100+
.missing(missingGeoPoint.toString())
101+
)
39102
.get();
40103
assertSearchResponse(response);
41-
GeoBounds bounds = response.getAggregations().get("bounds");
42-
assertThat(bounds.bottomRight().lat(), closeTo(2.0, 1E-5));
43-
assertThat(bounds.bottomRight().lon(), closeTo(1.0, 1E-5));
44-
assertThat(bounds.topLeft().lat(), closeTo(2.0, 1E-5));
45-
assertThat(bounds.topLeft().lon(), closeTo(1.0, 1E-5));
104+
validateResult(response.getAggregations().get(AGGREGATION_NAME));
46105
}
47106

48107
public void testGeoBounds() {
49-
SearchResponse response = client().prepareSearch("idx")
50-
.addAggregation(AggregationBuilders.geoBounds("bounds").field("location").missing("2,1"))
108+
GeoBoundsHelper.updateBoundsForGeoPoint(indexedGeoPoint, topLeft, bottomRight);
109+
final GeoPoint missingGeoPoint = RandomGeoGenerator.randomPoint(random());
110+
GeoBoundsHelper.updateBoundsForGeoPoint(missingGeoPoint, topLeft, bottomRight);
111+
SearchResponse response = client().prepareSearch(INDEX_NAME)
112+
.addAggregation(
113+
AggregationBuilders.geoBounds(AGGREGATION_NAME).field("location").wrapLongitude(false).missing(missingGeoPoint.toString())
114+
)
51115
.get();
52116
assertSearchResponse(response);
53-
GeoBounds bounds = response.getAggregations().get("bounds");
54-
assertThat(bounds.bottomRight().lat(), closeTo(1.0, 1E-5));
55-
assertThat(bounds.bottomRight().lon(), closeTo(2.0, 1E-5));
56-
assertThat(bounds.topLeft().lat(), closeTo(2.0, 1E-5));
57-
assertThat(bounds.topLeft().lon(), closeTo(1.0, 1E-5));
117+
validateResult(response.getAggregations().get(AGGREGATION_NAME));
118+
}
119+
120+
public void testGeoBoundsWithMissingShape() {
121+
// create GeoBounds for the indexed Field
122+
GeoBoundsHelper.updateBoundsForGeometry(indexedGeometry, topLeft, bottomRight);
123+
final Geometry missingGeometry = RandomGeoGeometryGenerator.randomGeometry(random());
124+
assert missingGeometry != null;
125+
GeoBoundsHelper.updateBoundsForGeometry(missingGeometry, topLeft, bottomRight);
126+
final SearchResponse response = client().prepareSearch(INDEX_NAME)
127+
.addAggregation(
128+
AggregationBuilders.geoBounds(AGGREGATION_NAME)
129+
.wrapLongitude(false)
130+
.field(GEO_SHAPE_FIELD_NAME)
131+
.missing(WKT.toWKT(missingGeometry))
132+
)
133+
.get();
134+
assertSearchResponse(response);
135+
validateResult(response.getAggregations().get(AGGREGATION_NAME));
136+
}
137+
138+
public void testUnmappedGeoBoundsOnGeoShape() {
139+
// We cannot useGeometry other than Point as for GeoBoundsAggregation as the Default Value for the
140+
// CoreValueSourceType is GeoPoint hence we need to use Point here.
141+
final Geometry missingGeometry = RandomGeoGeometryGenerator.randomPoint(random());
142+
final SearchResponse response = client().prepareSearch(INDEX_NAME)
143+
.addAggregation(AggregationBuilders.geoBounds(AGGREGATION_NAME).field(NON_EXISTENT_FIELD).missing(WKT.toWKT(missingGeometry)))
144+
.get();
145+
GeoBoundsHelper.updateBoundsForGeometry(missingGeometry, topLeft, bottomRight);
146+
assertSearchResponse(response);
147+
validateResult(response.getAggregations().get(AGGREGATION_NAME));
148+
}
149+
150+
private void validateResult(final GeoBounds bounds) {
151+
MatcherAssert.assertThat(bounds.bottomRight().lat(), closeTo(bottomRight.lat(), GEOHASH_TOLERANCE));
152+
MatcherAssert.assertThat(bounds.bottomRight().lon(), closeTo(bottomRight.lon(), GEOHASH_TOLERANCE));
153+
MatcherAssert.assertThat(bounds.topLeft().lat(), closeTo(topLeft.lat(), GEOHASH_TOLERANCE));
154+
MatcherAssert.assertThat(bounds.topLeft().lon(), closeTo(topLeft.lon(), GEOHASH_TOLERANCE));
58155
}
59156
}

0 commit comments

Comments
 (0)
Please sign in to comment.