Ver Fonte

Geo: Do not normalize the longitude with value -180 for Lucene shapes (#37299)

Lucene based shapes should not normalize the longitude value -180 to 180.
Ignacio Vera há 6 anos atrás
pai
commit
0a50821bb2

+ 5 - 1
server/src/main/java/org/elasticsearch/common/geo/builders/PolygonBuilder.java

@@ -342,6 +342,8 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
             holes = new org.apache.lucene.geo.Polygon[polygon.length - 1];
             for (int i = 0; i < holes.length; ++i) {
                 Coordinate[] coords = polygon[i+1];
+                //We do not have holes on the dateline as they get eliminated
+                //when breaking the polygon around it.
                 double[] x = new double[coords.length];
                 double[] y = new double[coords.length];
                 for (int c = 0; c < coords.length; ++c) {
@@ -357,7 +359,9 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
         double[] x = new double[shell.length];
         double[] y = new double[shell.length];
         for (int i = 0; i < shell.length; ++i) {
-            x[i] = normalizeLon(shell[i].x);
+            //Lucene Tessellator treats different +180 and -180 and we should keep the sign.
+            //normalizeLon method excludes -180.
+            x[i] = Math.abs(shell[i].x) > 180 ? normalizeLon(shell[i].x) : shell[i].x;
             y[i] = normalizeLat(shell[i].y);
         }
 

+ 1 - 1
server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java

@@ -1126,7 +1126,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
             ),
             new org.apache.lucene.geo.Polygon(
                 new double[] {12.142857142857142d, -12.142857142857142d, -10d, 10d, 12.142857142857142d},
-                new double[] {180d, 180d, -177d, -177d, 180d}
+                new double[] {-180d, -180d, -177d, -177d, -180d}
             )
         };
         assertGeometryEquals(luceneExpected, geometryCollectionGeoJson, false);

+ 83 - 0
server/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java

@@ -22,6 +22,7 @@ import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.cluster.ClusterState;
 import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
 import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.geo.builders.PointBuilder;
 import org.elasticsearch.common.geo.builders.ShapeBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentType;
@@ -158,6 +159,88 @@ public class GeoShapeIntegrationIT extends ESIntegTestCase {
         assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
     }
 
+    public void testIndexPolygonDateLine() throws Exception {
+        String mappingVector = "{\n" +
+            "    \"properties\": {\n" +
+            "      \"shape\": {\n" +
+            "        \"type\": \"geo_shape\"\n" +
+            "      }\n" +
+            "    }\n" +
+            "  }";
+
+        String mappingQuad = "{\n" +
+            "    \"properties\": {\n" +
+            "      \"shape\": {\n" +
+            "        \"type\": \"geo_shape\",\n" +
+            "        \"tree\": \"quadtree\"\n" +
+            "      }\n" +
+            "    }\n" +
+            "  }";
+
+
+        // create index
+        assertAcked(client().admin().indices().prepareCreate("vector").addMapping("doc", mappingVector, XContentType.JSON).get());
+        ensureGreen();
+
+        assertAcked(client().admin().indices().prepareCreate("quad").addMapping("doc", mappingQuad, XContentType.JSON).get());
+        ensureGreen();
+
+        String source = "{\n" +
+            "    \"shape\" : \"POLYGON((179 0, -179 0, -179 2, 179 2, 179 0))\""+
+            "}";
+
+        indexRandom(true, client().prepareIndex("quad", "doc", "0").setSource(source, XContentType.JSON));
+        indexRandom(true, client().prepareIndex("vector", "doc", "0").setSource(source, XContentType.JSON));
+
+        SearchResponse searchResponse = client().prepareSearch("quad").setQuery(
+            geoShapeQuery("shape", new PointBuilder(-179.75, 1))
+        ).get();
+
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+
+        searchResponse = client().prepareSearch("quad").setQuery(
+            geoShapeQuery("shape", new PointBuilder(90, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(0L));
+
+        searchResponse = client().prepareSearch("quad").setQuery(
+            geoShapeQuery("shape", new PointBuilder(-180, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+        searchResponse = client().prepareSearch("quad").setQuery(
+            geoShapeQuery("shape", new PointBuilder(180, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+
+        searchResponse = client().prepareSearch("vector").setQuery(
+            geoShapeQuery("shape", new PointBuilder(90, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(0L));
+
+        searchResponse = client().prepareSearch("vector").setQuery(
+            geoShapeQuery("shape", new PointBuilder(-179.75, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+
+        searchResponse = client().prepareSearch("vector").setQuery(
+            geoShapeQuery("shape", new PointBuilder(-180, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+
+        searchResponse = client().prepareSearch("vector").setQuery(
+            geoShapeQuery("shape", new PointBuilder(180, 1))
+        ).get();
+
+        assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
+    }
+
     private String findNodeName(String index) {
         ClusterState state = client().admin().cluster().prepareState().get().getState();
         IndexShardRoutingTable shard = state.getRoutingTable().index(index).shard(0);