Geo search across anti-meridian doesn't work, closes #363.

This commit is contained in:
kimchy 2010-09-10 16:04:10 +03:00
parent b31b0e979c
commit 4e661c165a
2 changed files with 104 additions and 6 deletions

View File

@ -75,6 +75,7 @@ public class GeoBoundingBoxFilter extends Filter {
final NumericFieldData latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, latFieldName);
final NumericFieldData lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, lonFieldName);
//checks to see if bounding box crosses 180 degrees
if (topLeft.lon > bottomRight.lon) {
return new GetDocSet(reader.maxDoc()) {
@Override public boolean get(int doc) throws IOException {
@ -86,17 +87,33 @@ public class GeoBoundingBoxFilter extends Filter {
double[] lats = latFieldData.doubleValues(doc);
double[] lons = latFieldData.doubleValues(doc);
for (int i = 0; i < lats.length; i++) {
if (topLeft.lon >= lons[i] && bottomRight.lon <= lons[i]
&& topLeft.lat >= lats[i] && bottomRight.lat <= lats[i]) {
return true;
double lat = lats[i];
double lon = lons[i];
if (lon < 0) {
if (-180.0 <= lon && bottomRight.lon >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
return true;
}
} else {
if (topLeft.lon <= lon && 180 >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
return true;
}
}
}
} else {
double lat = latFieldData.doubleValue(doc);
double lon = lonFieldData.doubleValue(doc);
if (topLeft.lon >= lon && bottomRight.lon <= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
return true;
if (lon < 0) {
if (-180.0 <= lon && bottomRight.lon >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
return true;
}
} else {
if (topLeft.lon <= lon && 180 >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
return true;
}
}
}
return false;

View File

@ -27,6 +27,7 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.elasticsearch.common.settings.ImmutableSettings.*;
import static org.elasticsearch.common.xcontent.XContentFactory.*;
import static org.elasticsearch.index.query.xcontent.FilterBuilders.*;
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
@ -117,5 +118,85 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("5")));
}
}
@Test public void limitsBoundingBoxTest() throws Exception {
try {
client.admin().indices().prepareDelete("test").execute().actionGet();
} catch (Exception e) {
// ignore
}
client.admin().indices().prepareCreate("test").setSettings(settingsBuilder().put("number_of_shards", "1")).execute().actionGet();
client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet();
client.prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 40).field("lon", -20).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 40).field("lon", -10).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 40).field("lon", 10).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 40).field("lon", 20).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "5").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 10).field("lon", -170).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "6").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 0).field("lon", -170).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "7").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", -10).field("lon", -170).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "8").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 10).field("lon", 170).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "9").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", 0).field("lon", 170).endObject()
.endObject()).execute().actionGet();
client.prepareIndex("test", "type1", "10").setSource(jsonBuilder().startObject()
.startObject("location").field("lat", -10).field("lon", 170).endObject()
.endObject()).execute().actionGet();
client.admin().indices().prepareRefresh().execute().actionGet();
SearchResponse searchResponse = client.prepareSearch()
.setQuery(filtered(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(41, -11).bottomRight(40, 9)))
.execute().actionGet();
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
assertThat(searchResponse.hits().hits().length, equalTo(1));
assertThat(searchResponse.hits().getAt(0).id(), equalTo("2"));
searchResponse = client.prepareSearch()
.setQuery(filtered(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(41, -9).bottomRight(40, 11)))
.execute().actionGet();
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
assertThat(searchResponse.hits().hits().length, equalTo(1));
assertThat(searchResponse.hits().getAt(0).id(), equalTo("3"));
searchResponse = client.prepareSearch()
.setQuery(filtered(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(11, 171).bottomRight(1, -169)))
.execute().actionGet();
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
assertThat(searchResponse.hits().hits().length, equalTo(1));
assertThat(searchResponse.hits().getAt(0).id(), equalTo("5"));
searchResponse = client.prepareSearch()
.setQuery(filtered(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(9, 169).bottomRight(-1, -171)))
.execute().actionGet();
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
assertThat(searchResponse.hits().hits().length, equalTo(1));
assertThat(searchResponse.hits().getAt(0).id(), equalTo("9"));
}
}