diff --git a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java index 67287b6cb30b6..ada4f60e17991 100644 --- a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java +++ b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java @@ -34,7 +34,8 @@ public enum ShapeRelation implements Writeable{ INTERSECTS("intersects"), DISJOINT("disjoint"), - WITHIN("within"); + WITHIN("within"), + CONTAINS("contains"); private final String relationName; diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java index c3bd9995a8e5b..5aad36cd27a38 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java @@ -361,6 +361,8 @@ public static SpatialArgs getArgs(ShapeBuilder shape, ShapeRelation relation) { return new SpatialArgs(SpatialOperation.Intersects, shape.build()); case WITHIN: return new SpatialArgs(SpatialOperation.IsWithin, shape.build()); + case CONTAINS: + return new SpatialArgs(SpatialOperation.Contains, shape.build()); default: throw new IllegalArgumentException("invalid relation [" + relation + "]"); } diff --git a/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java b/core/src/test/java/org/elasticsearch/search/geo/GeoShapeQueryTests.java similarity index 70% rename from core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java rename to core/src/test/java/org/elasticsearch/search/geo/GeoShapeQueryTests.java index 35466c31821b2..c7bf5b77d55c1 100644 --- a/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java +++ b/core/src/test/java/org/elasticsearch/search/geo/GeoShapeQueryTests.java @@ -19,25 +19,20 @@ package org.elasticsearch.search.geo; -import org.apache.lucene.util.LuceneTestCase; +import com.spatial4j.core.shape.Rectangle; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.common.geo.ShapeRelation; +import org.elasticsearch.common.geo.builders.EnvelopeBuilder; import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder; import org.elasticsearch.common.geo.builders.ShapeBuilder; import org.elasticsearch.common.geo.builders.ShapeBuilders; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.index.IndexService; -import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperParsingException; -import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper; import org.elasticsearch.index.query.GeoShapeQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.indices.IndicesService; -import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.test.geo.RandomShapeGenerator; import java.io.IOException; @@ -46,25 +41,25 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.index.query.QueryBuilders.geoIntersectionQuery; import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.geo.RandomShapeGenerator.createGeometryCollectionWithin; +import static org.elasticsearch.test.geo.RandomShapeGenerator.xRandomPoint; +import static org.elasticsearch.test.geo.RandomShapeGenerator.xRandomRectangle; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.*; -public class GeoShapeIntegrationIT extends ESIntegTestCase { +public class GeoShapeQueryTests extends ESSingleNodeTestCase { public void testNullShape() throws Exception { String mapping = XContentFactory.jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("location") .field("type", "geo_shape") .endObject().endObject() .endObject().endObject().string(); - assertAcked(prepareCreate("test").addMapping("type1", mapping)); + client().admin().indices().prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); - indexRandom(false, client().prepareIndex("test", "type1", "aNullshape").setSource("{\"location\": null}")); + client().prepareIndex("test", "type1", "aNullshape").setSource("{\"location\": null}").setRefresh(true) + .execute().actionGet(); GetResponse result = client().prepareGet("test", "type1", "aNullshape").execute().actionGet(); assertThat(result.getField("location"), nullValue()); } @@ -76,30 +71,28 @@ public void testIndexPointsFilterRectangle() throws Exception { .field("tree", "quadtree") .endObject().endObject() .endObject().endObject().string(); - assertAcked(prepareCreate("test").addMapping("type1", mapping)); + client().admin().indices().prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); - indexRandom(true, - - client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() - .field("name", "Document 1") - .startObject("location") - .field("type", "point") - .startArray("coordinates").value(-30).value(-30).endArray() - .endObject() - .endObject()), + client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() + .field("name", "Document 1") + .startObject("location") + .field("type", "point") + .startArray("coordinates").value(-30).value(-30).endArray() + .endObject() + .endObject()).setRefresh(true).execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() - .field("name", "Document 2") - .startObject("location") - .field("type", "point") - .startArray("coordinates").value(-45).value(-50).endArray() - .endObject() - .endObject())); + client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() + .field("name", "Document 2") + .startObject("location") + .field("type", "point") + .startArray("coordinates").value(-45).value(-50).endArray() + .endObject() + .endObject()).setRefresh(true).execute().actionGet(); ShapeBuilder shape = ShapeBuilders.newEnvelope().topLeft(-45, 45).bottomRight(45, -45); - SearchResponse searchResponse = client().prepareSearch() + SearchResponse searchResponse = client().prepareSearch("test").setTypes("type1") .setQuery(geoIntersectionQuery("location", shape)) .execute().actionGet(); @@ -108,7 +101,7 @@ public void testIndexPointsFilterRectangle() throws Exception { assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); - searchResponse = client().prepareSearch() + searchResponse = client().prepareSearch("test").setTypes("type1") .setQuery(geoShapeQuery("location", shape)) .execute().actionGet(); @@ -125,10 +118,10 @@ public void testEdgeCases() throws Exception { .field("tree", "quadtree") .endObject().endObject() .endObject().endObject().string(); - assertAcked(prepareCreate("test").addMapping("type1", mapping)); + client().admin().indices().prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); - indexRandom(true, client().prepareIndex("test", "type1", "blakely").setSource(jsonBuilder().startObject() + client().prepareIndex("test", "type1", "blakely").setSource(jsonBuilder().startObject() .field("name", "Blakely Island") .startObject("location") .field("type", "polygon") @@ -139,14 +132,13 @@ public void testEdgeCases() throws Exception { .startArray().value(-122.83).value(48.57).endArray() // close the polygon .endArray().endArray() .endObject() - .endObject())); - + .endObject()).setRefresh(true).execute().actionGet(); ShapeBuilder query = ShapeBuilders.newEnvelope().topLeft(-122.88, 48.62).bottomRight(-122.82, 48.54); // This search would fail if both geoshape indexing and geoshape filtering // used the bottom-level optimization in SpatialPrefixTree#recursiveGetNodes. - SearchResponse searchResponse = client().prepareSearch() + SearchResponse searchResponse = client().prepareSearch("test").setTypes("type1") .setQuery(geoIntersectionQuery("location", query)) .execute().actionGet(); @@ -163,24 +155,23 @@ public void testIndexedShapeReference() throws Exception { .field("tree", "quadtree") .endObject().endObject() .endObject().endObject().string(); - assertAcked(prepareCreate("test").addMapping("type1", mapping)); + client().admin().indices().prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); createIndex("shapes"); ensureGreen(); ShapeBuilder shape = ShapeBuilders.newEnvelope().topLeft(-45, 45).bottomRight(45, -45); - indexRandom(true, - client().prepareIndex("shapes", "shape_type", "Big_Rectangle").setSource(jsonBuilder().startObject() - .field("shape", shape).endObject()), - client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() + client().prepareIndex("shapes", "shape_type", "Big_Rectangle").setSource(jsonBuilder().startObject() + .field("shape", shape).endObject()).setRefresh(true).execute().actionGet(); + client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() .field("name", "Document 1") .startObject("location") .field("type", "point") .startArray("coordinates").value(-30).value(-30).endArray() .endObject() - .endObject())); + .endObject()).setRefresh(true).execute().actionGet(); - SearchResponse searchResponse = client().prepareSearch("test") + SearchResponse searchResponse = client().prepareSearch("test").setTypes("type1") .setQuery(geoIntersectionQuery("location", "Big_Rectangle", "shape_type")) .execute().actionGet(); @@ -220,17 +211,17 @@ private void assertUnmodified(ShapeBuilder builder) throws IOException { public void testShapeFetchingPath() throws Exception { createIndex("shapes"); - assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape")); + client().admin().indices().prepareCreate("test").addMapping("type", "location", "type=geo_shape").execute().actionGet(); String location = "\"location\" : {\"type\":\"polygon\", \"coordinates\":[[[-10,-10],[10,-10],[10,10],[-10,10],[-10,-10]]]}"; - indexRandom(true, - client().prepareIndex("shapes", "type", "1") + + client().prepareIndex("shapes", "type", "1") .setSource( String.format( Locale.ROOT, "{ %s, \"1\" : { %s, \"2\" : { %s, \"3\" : { %s } }} }", location, location, location, location ) - ), - client().prepareIndex("test", "type", "1") + ).setRefresh(true).execute().actionGet(); + client().prepareIndex("test", "type", "1") .setSource(jsonBuilder().startObject().startObject("location") .field("type", "polygon") .startArray("coordinates").startArray() @@ -240,8 +231,7 @@ public void testShapeFetchingPath() throws Exception { .startArray().value(-20).value(20).endArray() .startArray().value(-20).value(-20).endArray() .endArray().endArray() - .endObject().endObject())); - ensureSearchable("test", "shapes"); + .endObject().endObject()).setRefresh(true).execute().actionGet(); GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", "1", "type").relation(ShapeRelation.INTERSECTS) .indexedShapeIndex("shapes") @@ -305,27 +295,52 @@ public void testShapeFilterWithRandomGeoCollection() throws Exception { logger.info("Created Random GeometryCollection containing " + gcb.numShapes() + " shapes"); - createIndex("randshapes"); - assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape")); + client().admin().indices().prepareCreate("test").addMapping("type", "location", "type=geo_shape") + .execute().actionGet(); XContentBuilder docSource = gcb.toXContent(jsonBuilder().startObject().field("location"), null).endObject(); - indexRandom(true, client().prepareIndex("test", "type", "1").setSource(docSource)); - - ensureSearchable("test"); + client().prepareIndex("test", "type", "1").setSource(docSource).setRefresh(true).execute().actionGet(); ShapeBuilder filterShape = (gcb.getShapeAt(randomIntBetween(0, gcb.numShapes() - 1))); GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", filterShape); filter.relation(ShapeRelation.INTERSECTS); - SearchResponse result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) + SearchResponse result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); } + public void testContainsShapeQuery() throws Exception { + // Create a random geometry collection. + Rectangle mbr = xRandomRectangle(getRandom(), xRandomPoint(getRandom())); + GeometryCollectionBuilder gcb = createGeometryCollectionWithin(getRandom(), mbr); + + client().admin().indices().prepareCreate("test").addMapping("type", "location", "type=geo_shape") + .execute().actionGet(); + + XContentBuilder docSource = gcb.toXContent(jsonBuilder().startObject().field("location"), null).endObject(); + client().prepareIndex("test", "type", "1").setSource(docSource).setRefresh(true).execute().actionGet(); + + // index the mbr of the collection + EnvelopeBuilder env = new EnvelopeBuilder().topLeft(mbr.getMinX(), mbr.getMaxY()).bottomRight(mbr.getMaxX(), mbr.getMinY()); + docSource = env.toXContent(jsonBuilder().startObject().field("location"), null).endObject(); + client().prepareIndex("test", "type", "2").setSource(docSource).setRefresh(true).execute().actionGet(); + + ShapeBuilder filterShape = (gcb.getShapeAt(randomIntBetween(0, gcb.numShapes() - 1))); + GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", filterShape) + .relation(ShapeRelation.INTERSECTS); + SearchResponse response = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery()) + .setPostFilter(filter).get(); + assertSearchResponse(response); + + assertThat(response.getHits().totalHits(), greaterThan(0L)); + } + public void testShapeFilterWithDefinedGeoCollection() throws Exception { createIndex("shapes"); - assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape")); + client().admin().indices().prepareCreate("test").addMapping("type", "location", "type=geo_shape") + .execute().actionGet(); XContentBuilder docSource = jsonBuilder().startObject().startObject("location") .field("type", "geometrycollection") @@ -349,10 +364,8 @@ public void testShapeFilterWithDefinedGeoCollection() throws Exception { .endObject() .endArray() .endObject().endObject(); - indexRandom(true, - client().prepareIndex("test", "type", "1") - .setSource(docSource)); - ensureSearchable("test"); + client().prepareIndex("test", "type", "1") + .setSource(docSource).setRefresh(true).execute().actionGet(); GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery( "location", @@ -360,7 +373,7 @@ public void testShapeFilterWithDefinedGeoCollection() throws Exception { .polygon( ShapeBuilders.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0) .point(99.0, -1.0))).relation(ShapeRelation.INTERSECTS); - SearchResponse result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) + SearchResponse result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); @@ -369,7 +382,7 @@ public void testShapeFilterWithDefinedGeoCollection() throws Exception { ShapeBuilders.newGeometryCollection().polygon( ShapeBuilders.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0) .point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS); - result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) + result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 0); @@ -378,65 +391,12 @@ public void testShapeFilterWithDefinedGeoCollection() throws Exception { .polygon( ShapeBuilders.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0) .point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS); - result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) + result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); } - /** - * Test that orientation parameter correctly persists across cluster restart - */ - public void testOrientationPersistence() throws Exception { - String idxName = "orientation"; - String mapping = XContentFactory.jsonBuilder().startObject().startObject("shape") - .startObject("properties").startObject("location") - .field("type", "geo_shape") - .field("orientation", "left") - .endObject().endObject() - .endObject().endObject().string(); - - // create index - assertAcked(prepareCreate(idxName).addMapping("shape", mapping)); - - mapping = XContentFactory.jsonBuilder().startObject().startObject("shape") - .startObject("properties").startObject("location") - .field("type", "geo_shape") - .field("orientation", "right") - .endObject().endObject() - .endObject().endObject().string(); - - assertAcked(prepareCreate(idxName+"2").addMapping("shape", mapping)); - ensureGreen(idxName, idxName+"2"); - - internalCluster().fullRestart(); - ensureGreen(idxName, idxName+"2"); - - // left orientation test - IndicesService indicesService = internalCluster().getInstance(IndicesService.class, findNodeName(idxName)); - IndexService indexService = indicesService.indexService(idxName); - MappedFieldType fieldType = indexService.mapperService().smartNameFieldType("location"); - assertThat(fieldType, instanceOf(GeoShapeFieldMapper.GeoShapeFieldType.class)); - - GeoShapeFieldMapper.GeoShapeFieldType gsfm = (GeoShapeFieldMapper.GeoShapeFieldType)fieldType; - ShapeBuilder.Orientation orientation = gsfm.orientation(); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.CLOCKWISE)); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.LEFT)); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.CW)); - - // right orientation test - indicesService = internalCluster().getInstance(IndicesService.class, findNodeName(idxName+"2")); - indexService = indicesService.indexService(idxName+"2"); - fieldType = indexService.mapperService().smartNameFieldType("location"); - assertThat(fieldType, instanceOf(GeoShapeFieldMapper.GeoShapeFieldType.class)); - - gsfm = (GeoShapeFieldMapper.GeoShapeFieldType)fieldType; - orientation = gsfm.orientation(); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.COUNTER_CLOCKWISE)); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.RIGHT)); - assertThat(orientation, equalTo(ShapeBuilder.Orientation.CCW)); - } - public void testPointsOnly() throws Exception { String mapping = XContentFactory.jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("location") @@ -448,31 +408,25 @@ public void testPointsOnly() throws Exception { .endObject().endObject() .endObject().endObject().string(); - assertAcked(prepareCreate("geo_points_only").addMapping("type1", mapping)); + client().admin().indices().prepareCreate("geo_points_only").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); ShapeBuilder shape = RandomShapeGenerator.createShape(random()); try { - index("geo_points_only", "type1", "1", jsonBuilder().startObject().field("location", shape).endObject()); + client().prepareIndex("geo_points_only", "type1", "1") + .setSource(jsonBuilder().startObject().field("location", shape).endObject()) + .setRefresh(true).execute().actionGet(); } catch (MapperParsingException e) { // RandomShapeGenerator created something other than a POINT type, verify the correct exception is thrown assertThat(e.getCause().getMessage(), containsString("is configured for points only")); return; } - refresh(); // test that point was inserted - SearchResponse response = client().prepareSearch() + SearchResponse response = client().prepareSearch("geo_points_only").setTypes("type1") .setQuery(geoIntersectionQuery("location", shape)) .execute().actionGet(); assertEquals(1, response.getHits().getTotalHits()); } - - private String findNodeName(String index) { - ClusterState state = client().admin().cluster().prepareState().get().getState(); - IndexShardRoutingTable shard = state.getRoutingTable().index(index).shard(0); - String nodeId = shard.assignedShards().get(0).currentNodeId(); - return state.getNodes().get(nodeId).name(); - } } diff --git a/core/src/test/java/org/elasticsearch/test/geo/RandomShapeGenerator.java b/core/src/test/java/org/elasticsearch/test/geo/RandomShapeGenerator.java index ddea8145d0719..f533e851360d4 100644 --- a/core/src/test/java/org/elasticsearch/test/geo/RandomShapeGenerator.java +++ b/core/src/test/java/org/elasticsearch/test/geo/RandomShapeGenerator.java @@ -40,6 +40,7 @@ import org.elasticsearch.common.geo.builders.PointCollection; import org.elasticsearch.common.geo.builders.PolygonBuilder; import org.elasticsearch.common.geo.builders.ShapeBuilder; +import org.elasticsearch.search.geo.GeoShapeQueryTests; import org.junit.Assert; import java.util.Random; @@ -155,7 +156,7 @@ private static ShapeBuilder createShape(Random r, Point nearPoint, Rectangle wit /** * Creates a random shape useful for randomized testing, NOTE: exercise caution when using this to build random GeometryCollections * as creating a large random number of random shapes can result in massive resource consumption - * see: {@link org.elasticsearch.search.geo.GeoShapeIntegrationIT#testShapeFilterWithRandomGeoCollection} + * see: {@link GeoShapeQueryTests#testShapeFilterWithRandomGeoCollection} * * The following options are included * @param nearPoint Create a shape near a provided point diff --git a/docs/reference/query-dsl/geo-shape-query.asciidoc b/docs/reference/query-dsl/geo-shape-query.asciidoc index 77deabcad91a6..a6d13562bb0ba 100644 --- a/docs/reference/query-dsl/geo-shape-query.asciidoc +++ b/docs/reference/query-dsl/geo-shape-query.asciidoc @@ -50,7 +50,8 @@ The following query will find the point using the Elasticsearch's "shape": { "type": "envelope", "coordinates" : [[13.0, 53.0], [14.0, 52.0]] - } + }, + "relation": "within" } } } @@ -61,7 +62,7 @@ The following query will find the point using the Elasticsearch's ==== Pre-Indexed Shape -The Filter also supports using a shape which has already been indexed in +The Query also supports using a shape which has already been indexed in another index and/or index type. This is particularly useful for when you have a pre-defined list of shapes which are useful to your application and you want to reference this using a logical name (for @@ -101,3 +102,15 @@ shape: } -------------------------------------------------- +==== Spatial Relations + +The Query supports the following spatial relations: + +* `INTERSECTS` - (default) Return all documents whose `geo_shape` field +intersects the query geometry. +* `DISJOINT` - Return all documents whose `geo_shape` field +has nothing in common with the query geometry. +* `WITHIN` - Return all documents whose `geo_shape` field +is within the query geometry. +* `CONTAINS` - Return all documents whose `geo_shape` field +contains the query geometry. \ No newline at end of file diff --git a/plugins/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoShapeIntegrationTests.java b/plugins/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoShapeIntegrationTests.java new file mode 100644 index 0000000000000..37132c5a923bc --- /dev/null +++ b/plugins/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoShapeIntegrationTests.java @@ -0,0 +1,108 @@ +/* + * 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.messy.tests; + +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.routing.IndexShardRoutingTable; +import org.elasticsearch.common.geo.builders.ShapeBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.index.IndexService; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper; +import org.elasticsearch.indices.IndicesService; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.script.groovy.GroovyPlugin; +import org.elasticsearch.test.ESIntegTestCase; + +import java.util.Collection; +import java.util.Collections; + +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; + +/** + */ +public class GeoShapeIntegrationTests extends ESIntegTestCase { + + @Override + protected Collection> nodePlugins() { + return Collections.singleton(GroovyPlugin.class); + } + + /** + * Test that orientation parameter correctly persists across cluster restart + */ + public void testOrientationPersistence() throws Exception { + String idxName = "orientation"; + String mapping = XContentFactory.jsonBuilder().startObject().startObject("shape") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("orientation", "left") + .endObject().endObject() + .endObject().endObject().string(); + + // create index + assertAcked(prepareCreate(idxName).addMapping("shape", mapping)); + + mapping = XContentFactory.jsonBuilder().startObject().startObject("shape") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("orientation", "right") + .endObject().endObject() + .endObject().endObject().string(); + + assertAcked(prepareCreate(idxName+"2").addMapping("shape", mapping)); + ensureGreen(idxName, idxName+"2"); + + internalCluster().fullRestart(); + ensureGreen(idxName, idxName+"2"); + + // left orientation test + IndicesService indicesService = internalCluster().getInstance(IndicesService.class, findNodeName(idxName)); + IndexService indexService = indicesService.indexService(idxName); + MappedFieldType fieldType = indexService.mapperService().smartNameFieldType("location"); + assertThat(fieldType, instanceOf(GeoShapeFieldMapper.GeoShapeFieldType.class)); + + GeoShapeFieldMapper.GeoShapeFieldType gsfm = (GeoShapeFieldMapper.GeoShapeFieldType)fieldType; + ShapeBuilder.Orientation orientation = gsfm.orientation(); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.CLOCKWISE)); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.LEFT)); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.CW)); + + // right orientation test + indicesService = internalCluster().getInstance(IndicesService.class, findNodeName(idxName+"2")); + indexService = indicesService.indexService(idxName+"2"); + fieldType = indexService.mapperService().smartNameFieldType("location"); + assertThat(fieldType, instanceOf(GeoShapeFieldMapper.GeoShapeFieldType.class)); + + gsfm = (GeoShapeFieldMapper.GeoShapeFieldType)fieldType; + orientation = gsfm.orientation(); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.COUNTER_CLOCKWISE)); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.RIGHT)); + assertThat(orientation, equalTo(ShapeBuilder.Orientation.CCW)); + } + + private String findNodeName(String index) { + ClusterState state = client().admin().cluster().prepareState().get().getState(); + IndexShardRoutingTable shard = state.getRoutingTable().index(index).shard(0); + String nodeId = shard.assignedShards().get(0).currentNodeId(); + return state.getNodes().get(nodeId).name(); + } +}