From f8d75faaad0aad4305d18a9f1a433d994c2f7f3d Mon Sep 17 00:00:00 2001 From: Colin Goodheart-Smithe Date: Tue, 19 Aug 2014 17:11:52 +0100 Subject: [PATCH] Geo: Fixes BoundingBox across complete longitudinal range Adds a special case to the GeoBoundingBoxFilterParser so that the left of the box is not normalised in the case where left and right are 360 apart. Before this change the left would be normalised to 180 in this case and the filter would only match points with a longitude of 180 (or -180). Closes #5128 --- .../query/GeoBoundingBoxFilterParser.java | 13 +++- .../search/geo/GeoBoundingBoxTests.java | 75 +++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxFilterParser.java b/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxFilterParser.java index 14e520418fb..80eb326d723 100644 --- a/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxFilterParser.java @@ -155,10 +155,17 @@ public class GeoBoundingBoxFilterParser implements FilterParser { final GeoPoint topLeft = sparse.reset(top, left); //just keep the object final GeoPoint bottomRight = new GeoPoint(bottom, right); - + if (normalize) { - GeoUtils.normalizePoint(topLeft); - GeoUtils.normalizePoint(bottomRight); + // Special case: if the difference bettween the left and right is 360 and the right is greater than the left, we are asking for + // the complete longitude range so need to set longitude to the complete longditude range + boolean completeLonRange = ((right - left) % 360 == 0 && right > left); + GeoUtils.normalizePoint(topLeft, true, !completeLonRange); + GeoUtils.normalizePoint(bottomRight, true, !completeLonRange); + if (completeLonRange) { + topLeft.resetLon(-180); + bottomRight.resetLon(180); + } } MapperService.SmartNameFieldMappers smartMappers = parseContext.smartFieldMappers(fieldName); diff --git a/src/test/java/org/elasticsearch/search/geo/GeoBoundingBoxTests.java b/src/test/java/org/elasticsearch/search/geo/GeoBoundingBoxTests.java index edf031bb542..0773964acc1 100644 --- a/src/test/java/org/elasticsearch/search/geo/GeoBoundingBoxTests.java +++ b/src/test/java/org/elasticsearch/search/geo/GeoBoundingBoxTests.java @@ -261,5 +261,80 @@ public class GeoBoundingBoxTests extends ElasticsearchIntegrationTest { ).execute().actionGet(); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); } + + @Test + public void completeLonRangeTest() throws Exception { + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location").field("type", "geo_point").field("lat_lon", true).endObject().endObject() + .endObject().endObject(); + assertAcked(prepareCreate("test").addMapping("type1", xContentBuilder)); + ensureGreen(); + + client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() + .field("userid", 880) + .field("title", "Place in Stockholm") + .startObject("location").field("lat", 59.328355000000002).field("lon", 18.036842).endObject() + .endObject()) + .setRefresh(true) + .execute().actionGet(); + + client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() + .field("userid", 534) + .field("title", "Place in Montreal") + .startObject("location").field("lat", 45.509526999999999).field("lon", -73.570986000000005).endObject() + .endObject()) + .setRefresh(true) + .execute().actionGet(); + + SearchResponse searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(50, -180).bottomRight(-50, 180)) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(50, -180).bottomRight(-50, 180).type("indexed")) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(90, -180).bottomRight(-90, 180)) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(90, -180).bottomRight(-90, 180).type("indexed")) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); + + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(50, 0).bottomRight(-50, 360)) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(50, 0).bottomRight(-50, 360).type("indexed")) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(90, 0).bottomRight(-90, 360)) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); + searchResponse = client().prepareSearch() + .setQuery( + filteredQuery(matchAllQuery(), + geoBoundingBoxFilter("location").topLeft(90, 0).bottomRight(-90, 360).type("indexed")) + ).execute().actionGet(); + assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); + } }