Geo Distance Filter Bounding Box Optimization, closes #1261.
This commit is contained in:
parent
4bacebe860
commit
7a4fca2c1a
|
@ -12,6 +12,7 @@
|
||||||
<w>attr</w>
|
<w>attr</w>
|
||||||
<w>auth</w>
|
<w>auth</w>
|
||||||
<w>banon</w>
|
<w>banon</w>
|
||||||
|
<w>bbox</w>
|
||||||
<w>bindhost</w>
|
<w>bindhost</w>
|
||||||
<w>birthdate</w>
|
<w>birthdate</w>
|
||||||
<w>bitset</w>
|
<w>bitset</w>
|
||||||
|
|
|
@ -104,46 +104,63 @@ public class GeoDistanceSearchBenchmark {
|
||||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
System.err.println("--> Warming up (ARC)");
|
System.err.println("--> Warming up (ARC) - optimize_bbox");
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
for (int i = 0; i < NUM_WARM; i++) {
|
for (int i = 0; i < NUM_WARM; i++) {
|
||||||
run(client, GeoDistance.ARC);
|
run(client, GeoDistance.ARC, true);
|
||||||
}
|
}
|
||||||
long totalTime = System.currentTimeMillis() - start;
|
long totalTime = System.currentTimeMillis() - start;
|
||||||
System.out.println("--> Warmup (ARC) " + (totalTime / NUM_WARM) + "ms");
|
System.err.println("--> Warmup (ARC) - optimize_bbox " + (totalTime / NUM_WARM) + "ms");
|
||||||
|
|
||||||
System.err.println("--> Perf (ARC)");
|
System.err.println("--> Perf (ARC) - optimize_bbox");
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
for (int i = 0; i < NUM_RUNS; i++) {
|
for (int i = 0; i < NUM_RUNS; i++) {
|
||||||
run(client, GeoDistance.ARC);
|
run(client, GeoDistance.ARC, true);
|
||||||
}
|
}
|
||||||
totalTime = System.currentTimeMillis() - start;
|
totalTime = System.currentTimeMillis() - start;
|
||||||
System.out.println("--> Perf (ARC) " + (totalTime / NUM_RUNS) + "ms");
|
System.err.println("--> Perf (ARC) - optimize_bbox " + (totalTime / NUM_RUNS) + "ms");
|
||||||
|
|
||||||
|
System.err.println("--> Warming up (ARC) - no optimize_bbox");
|
||||||
|
start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < NUM_WARM; i++) {
|
||||||
|
run(client, GeoDistance.ARC, false);
|
||||||
|
}
|
||||||
|
totalTime = System.currentTimeMillis() - start;
|
||||||
|
System.err.println("--> Warmup (ARC) - no optimize_bbox " + (totalTime / NUM_WARM) + "ms");
|
||||||
|
|
||||||
|
System.err.println("--> Perf (ARC) - no optimize_bbox");
|
||||||
|
start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < NUM_RUNS; i++) {
|
||||||
|
run(client, GeoDistance.ARC, false);
|
||||||
|
}
|
||||||
|
totalTime = System.currentTimeMillis() - start;
|
||||||
|
System.err.println("--> Perf (ARC) - no optimize_bbox " + (totalTime / NUM_RUNS) + "ms");
|
||||||
|
|
||||||
System.err.println("--> Warming up (PLANE)");
|
System.err.println("--> Warming up (PLANE)");
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
for (int i = 0; i < NUM_WARM; i++) {
|
for (int i = 0; i < NUM_WARM; i++) {
|
||||||
run(client, GeoDistance.PLANE);
|
run(client, GeoDistance.PLANE, true);
|
||||||
}
|
}
|
||||||
totalTime = System.currentTimeMillis() - start;
|
totalTime = System.currentTimeMillis() - start;
|
||||||
System.out.println("--> Warmup (PLANE) " + (totalTime / NUM_WARM) + "ms");
|
System.err.println("--> Warmup (PLANE) " + (totalTime / NUM_WARM) + "ms");
|
||||||
|
|
||||||
System.err.println("--> Perf (PLANE)");
|
System.err.println("--> Perf (PLANE)");
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
for (int i = 0; i < NUM_RUNS; i++) {
|
for (int i = 0; i < NUM_RUNS; i++) {
|
||||||
run(client, GeoDistance.PLANE);
|
run(client, GeoDistance.PLANE, true);
|
||||||
}
|
}
|
||||||
totalTime = System.currentTimeMillis() - start;
|
totalTime = System.currentTimeMillis() - start;
|
||||||
System.out.println("--> Perf (PLANE) " + (totalTime / NUM_RUNS) + "ms");
|
System.err.println("--> Perf (PLANE) " + (totalTime / NUM_RUNS) + "ms");
|
||||||
|
|
||||||
node.close();
|
node.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void run(Client client, GeoDistance geoDistance) {
|
public static void run(Client client, GeoDistance geoDistance, boolean optimizeBbox) {
|
||||||
client.prepareSearch() // from NY
|
client.prepareSearch() // from NY
|
||||||
.setSearchType(SearchType.COUNT)
|
.setSearchType(SearchType.COUNT)
|
||||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location")
|
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location")
|
||||||
.distance("2km")
|
.distance("2km")
|
||||||
|
.optimizeBbox(optimizeBbox)
|
||||||
.geoDistance(geoDistance)
|
.geoDistance(geoDistance)
|
||||||
.point(40.7143528, -74.0059731)))
|
.point(40.7143528, -74.0059731)))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
|
@ -43,6 +43,14 @@ public class GeoPointDocFieldData extends DocFieldData<GeoPointFieldData> {
|
||||||
return fieldData.factorDistance(docId, DistanceUnit.MILES, lat, lon);
|
return fieldData.factorDistance(docId, DistanceUnit.MILES, lat, lon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double factorDistance02(double lat, double lon) {
|
||||||
|
return fieldData.factorDistance(docId, DistanceUnit.MILES, lat, lon) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double factorDistance13(double lat, double lon) {
|
||||||
|
return fieldData.factorDistance(docId, DistanceUnit.MILES, lat, lon) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
public double arcDistance(double lat, double lon) {
|
public double arcDistance(double lat, double lon) {
|
||||||
return fieldData.arcDistance(docId, DistanceUnit.MILES, lat, lon);
|
return fieldData.arcDistance(docId, DistanceUnit.MILES, lat, lon);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.index.search.geo.GeoBoundingBoxFilter;
|
import org.elasticsearch.index.search.geo.Point;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private GeoBoundingBoxFilter.Point topLeft;
|
private Point topLeft;
|
||||||
|
|
||||||
private String topLeftGeohash;
|
private String topLeftGeohash;
|
||||||
|
|
||||||
private GeoBoundingBoxFilter.Point bottomRight;
|
private Point bottomRight;
|
||||||
|
|
||||||
private String bottomRightGeohash;
|
private String bottomRightGeohash;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
||||||
* @param lon The longitude
|
* @param lon The longitude
|
||||||
*/
|
*/
|
||||||
public GeoBoundingBoxFilterBuilder topLeft(double lat, double lon) {
|
public GeoBoundingBoxFilterBuilder topLeft(double lat, double lon) {
|
||||||
topLeft = new GeoBoundingBoxFilter.Point();
|
topLeft = new Point();
|
||||||
topLeft.lat = lat;
|
topLeft.lat = lat;
|
||||||
topLeft.lon = lon;
|
topLeft.lon = lon;
|
||||||
return this;
|
return this;
|
||||||
|
@ -68,7 +68,7 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
||||||
* @param lon The longitude
|
* @param lon The longitude
|
||||||
*/
|
*/
|
||||||
public GeoBoundingBoxFilterBuilder bottomRight(double lat, double lon) {
|
public GeoBoundingBoxFilterBuilder bottomRight(double lat, double lon) {
|
||||||
bottomRight = new GeoBoundingBoxFilter.Point();
|
bottomRight = new Point();
|
||||||
bottomRight.lat = lat;
|
bottomRight.lat = lat;
|
||||||
bottomRight.lon = lon;
|
bottomRight.lon = lon;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.index.mapper.geo.GeoPointFieldDataType;
|
||||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||||
import org.elasticsearch.index.search.geo.GeoBoundingBoxFilter;
|
import org.elasticsearch.index.search.geo.GeoBoundingBoxFilter;
|
||||||
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
||||||
|
import org.elasticsearch.index.search.geo.Point;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -54,8 +55,8 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
||||||
boolean cache = false;
|
boolean cache = false;
|
||||||
CacheKeyFilter.Key cacheKey = null;
|
CacheKeyFilter.Key cacheKey = null;
|
||||||
String fieldName = null;
|
String fieldName = null;
|
||||||
GeoBoundingBoxFilter.Point topLeft = new GeoBoundingBoxFilter.Point();
|
Point topLeft = new Point();
|
||||||
GeoBoundingBoxFilter.Point bottomRight = new GeoBoundingBoxFilter.Point();
|
Point bottomRight = new Point();
|
||||||
|
|
||||||
String filterName = null;
|
String filterName = null;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
|
@ -70,7 +71,7 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||||
GeoBoundingBoxFilter.Point point = null;
|
Point point = null;
|
||||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||||
point = topLeft;
|
point = topLeft;
|
||||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||||
|
@ -87,7 +88,7 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
GeoBoundingBoxFilter.Point point = null;
|
Point point = null;
|
||||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||||
point = topLeft;
|
point = topLeft;
|
||||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||||
|
@ -115,7 +116,7 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
||||||
if ("field".equals(currentFieldName)) {
|
if ("field".equals(currentFieldName)) {
|
||||||
fieldName = parser.text();
|
fieldName = parser.text();
|
||||||
} else {
|
} else {
|
||||||
GeoBoundingBoxFilter.Point point = null;
|
Point point = null;
|
||||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||||
point = topLeft;
|
point = topLeft;
|
||||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||||
|
|
|
@ -42,6 +42,8 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
||||||
|
|
||||||
private GeoDistance geoDistance;
|
private GeoDistance geoDistance;
|
||||||
|
|
||||||
|
private Boolean optimizeBbox;
|
||||||
|
|
||||||
private Boolean cache;
|
private Boolean cache;
|
||||||
private String cacheKey;
|
private String cacheKey;
|
||||||
|
|
||||||
|
@ -87,6 +89,11 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GeoDistanceFilterBuilder optimizeBbox(boolean optimizeBbox) {
|
||||||
|
this.optimizeBbox = optimizeBbox;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the filter name for the filter that can be used when searching for matched_filters per hit.
|
* Sets the filter name for the filter that can be used when searching for matched_filters per hit.
|
||||||
*/
|
*/
|
||||||
|
@ -119,6 +126,9 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
||||||
if (geoDistance != null) {
|
if (geoDistance != null) {
|
||||||
builder.field("distance_type", geoDistance.name().toLowerCase());
|
builder.field("distance_type", geoDistance.name().toLowerCase());
|
||||||
}
|
}
|
||||||
|
if (optimizeBbox != null) {
|
||||||
|
builder.field("optimize_bbox", optimizeBbox.booleanValue());
|
||||||
|
}
|
||||||
if (filterName != null) {
|
if (filterName != null) {
|
||||||
builder.field("_name", filterName);
|
builder.field("_name", filterName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
||||||
Object vDistance = null;
|
Object vDistance = null;
|
||||||
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
||||||
GeoDistance geoDistance = GeoDistance.ARC;
|
GeoDistance geoDistance = GeoDistance.ARC;
|
||||||
|
boolean optimizeBbox = true;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
|
@ -132,6 +133,8 @@ public class GeoDistanceFilterParser implements FilterParser {
|
||||||
cache = parser.booleanValue();
|
cache = parser.booleanValue();
|
||||||
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
||||||
cacheKey = new CacheKeyFilter.Key(parser.text());
|
cacheKey = new CacheKeyFilter.Key(parser.text());
|
||||||
|
} else if ("optimize_bbox".equals(currentFieldName) || "optimizeBbox".equals(currentFieldName)) {
|
||||||
|
optimizeBbox = parser.booleanValue();
|
||||||
} else {
|
} else {
|
||||||
// assume the value is the actual value
|
// assume the value is the actual value
|
||||||
String value = parser.text();
|
String value = parser.text();
|
||||||
|
@ -166,7 +169,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
fieldName = mapper.names().indexName();
|
fieldName = mapper.names().indexName();
|
||||||
|
|
||||||
Filter filter = new GeoDistanceFilter(lat, lon, distance, geoDistance, fieldName, parseContext.indexCache().fieldData());
|
Filter filter = new GeoDistanceFilter(lat, lon, distance, geoDistance, fieldName, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||||
if (cache) {
|
if (cache) {
|
||||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
||||||
boolean includeUpper = true;
|
boolean includeUpper = true;
|
||||||
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
||||||
GeoDistance geoDistance = GeoDistance.ARC;
|
GeoDistance geoDistance = GeoDistance.ARC;
|
||||||
|
boolean optimizeBbox = true;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
|
@ -181,6 +182,8 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
||||||
cache = parser.booleanValue();
|
cache = parser.booleanValue();
|
||||||
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
||||||
cacheKey = new CacheKeyFilter.Key(parser.text());
|
cacheKey = new CacheKeyFilter.Key(parser.text());
|
||||||
|
} else if ("optimize_bbox".equals(currentFieldName) || "optimizeBbox".equals(currentFieldName)) {
|
||||||
|
optimizeBbox = parser.booleanValue();
|
||||||
} else {
|
} else {
|
||||||
// assume the value is the actual value
|
// assume the value is the actual value
|
||||||
String value = parser.text();
|
String value = parser.text();
|
||||||
|
@ -223,7 +226,7 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
fieldName = mapper.names().indexName();
|
fieldName = mapper.names().indexName();
|
||||||
|
|
||||||
Filter filter = new GeoDistanceRangeFilter(lat, lon, from, to, includeLower, includeUpper, geoDistance, fieldName, parseContext.indexCache().fieldData());
|
Filter filter = new GeoDistanceRangeFilter(lat, lon, from, to, includeLower, includeUpper, geoDistance, fieldName, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||||
if (cache) {
|
if (cache) {
|
||||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.index.query;
|
||||||
import org.elasticsearch.common.collect.Lists;
|
import org.elasticsearch.common.collect.Lists;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
||||||
import org.elasticsearch.index.search.geo.GeoPolygonFilter;
|
import org.elasticsearch.index.search.geo.Point;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -34,7 +34,7 @@ public class GeoPolygonFilterBuilder extends BaseFilterBuilder {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final List<GeoPolygonFilter.Point> points = Lists.newArrayList();
|
private final List<Point> points = Lists.newArrayList();
|
||||||
|
|
||||||
private Boolean cache;
|
private Boolean cache;
|
||||||
private String cacheKey;
|
private String cacheKey;
|
||||||
|
@ -53,7 +53,7 @@ public class GeoPolygonFilterBuilder extends BaseFilterBuilder {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public GeoPolygonFilterBuilder addPoint(double lat, double lon) {
|
public GeoPolygonFilterBuilder addPoint(double lat, double lon) {
|
||||||
points.add(new GeoPolygonFilter.Point(lat, lon));
|
points.add(new Point(lat, lon));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ public class GeoPolygonFilterBuilder extends BaseFilterBuilder {
|
||||||
|
|
||||||
builder.startObject(name);
|
builder.startObject(name);
|
||||||
builder.startArray("points");
|
builder.startArray("points");
|
||||||
for (GeoPolygonFilter.Point point : points) {
|
for (Point point : points) {
|
||||||
builder.startArray().value(point.lon).value(point.lat).endArray();
|
builder.startArray().value(point.lon).value(point.lat).endArray();
|
||||||
}
|
}
|
||||||
builder.endArray();
|
builder.endArray();
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.elasticsearch.index.mapper.geo.GeoPointFieldDataType;
|
||||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||||
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
||||||
import org.elasticsearch.index.search.geo.GeoPolygonFilter;
|
import org.elasticsearch.index.search.geo.GeoPolygonFilter;
|
||||||
|
import org.elasticsearch.index.search.geo.Point;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -67,7 +68,7 @@ public class GeoPolygonFilterParser implements FilterParser {
|
||||||
boolean cache = false;
|
boolean cache = false;
|
||||||
CacheKeyFilter.Key cacheKey = null;
|
CacheKeyFilter.Key cacheKey = null;
|
||||||
String fieldName = null;
|
String fieldName = null;
|
||||||
List<GeoPolygonFilter.Point> points = Lists.newArrayList();
|
List<Point> points = Lists.newArrayList();
|
||||||
|
|
||||||
|
|
||||||
String filterName = null;
|
String filterName = null;
|
||||||
|
@ -89,7 +90,7 @@ public class GeoPolygonFilterParser implements FilterParser {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
Point point = new Point();
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
point.lon = parser.doubleValue();
|
point.lon = parser.doubleValue();
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
|
@ -99,7 +100,7 @@ public class GeoPolygonFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
points.add(point);
|
points.add(point);
|
||||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
Point point = new Point();
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
|
@ -117,7 +118,7 @@ public class GeoPolygonFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
points.add(point);
|
points.add(point);
|
||||||
} else if (token.isValue()) {
|
} else if (token.isValue()) {
|
||||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
Point point = new Point();
|
||||||
String value = parser.text();
|
String value = parser.text();
|
||||||
int comma = value.indexOf(',');
|
int comma = value.indexOf(',');
|
||||||
if (comma != -1) {
|
if (comma != -1) {
|
||||||
|
@ -159,7 +160,7 @@ public class GeoPolygonFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
fieldName = mapper.names().indexName();
|
fieldName = mapper.names().indexName();
|
||||||
|
|
||||||
Filter filter = new GeoPolygonFilter(points.toArray(new GeoPolygonFilter.Point[points.size()]), fieldName, parseContext.indexCache().fieldData());
|
Filter filter = new GeoPolygonFilter(points.toArray(new Point[points.size()]), fieldName, parseContext.indexCache().fieldData());
|
||||||
if (cache) {
|
if (cache) {
|
||||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class GeoBoundingBoxFilter extends Filter {
|
||||||
for (int i = 0; i < lats.length; i++) {
|
for (int i = 0; i < lats.length; i++) {
|
||||||
double lat = lats[i];
|
double lat = lats[i];
|
||||||
double lon = lons[i];
|
double lon = lons[i];
|
||||||
if (((topLeft.lon <= lon && 180 >= lon) || (-180 <= lon && bottomRight.lon >= lon)) &&
|
if (((topLeft.lon <= lon || bottomRight.lon >= lon)) &&
|
||||||
(topLeft.lat >= lat && bottomRight.lat <= lat)) {
|
(topLeft.lat >= lat && bottomRight.lat <= lat)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class GeoBoundingBoxFilter extends Filter {
|
||||||
double lat = fieldData.latValue(doc);
|
double lat = fieldData.latValue(doc);
|
||||||
double lon = fieldData.lonValue(doc);
|
double lon = fieldData.lonValue(doc);
|
||||||
|
|
||||||
if (((topLeft.lon <= lon && 180 >= lon) || (-180 <= lon && bottomRight.lon >= lon)) &&
|
if (((topLeft.lon <= lon || bottomRight.lon >= lon)) &&
|
||||||
(topLeft.lat >= lat && bottomRight.lat <= lat)) {
|
(topLeft.lat >= lat && bottomRight.lat <= lat)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -165,9 +165,4 @@ public class GeoBoundingBoxFilter extends Filter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Point {
|
|
||||||
public double lat;
|
|
||||||
public double lon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,44 @@ public enum GeoDistance {
|
||||||
|
|
||||||
public abstract FixedSourceDistance fixedSourceDistance(double sourceLatitude, double sourceLongitude, DistanceUnit unit);
|
public abstract FixedSourceDistance fixedSourceDistance(double sourceLatitude, double sourceLongitude, DistanceUnit unit);
|
||||||
|
|
||||||
|
private static final double MIN_LAT = Math.toRadians(-90d); // -PI/2
|
||||||
|
private static final double MAX_LAT = Math.toRadians(90d); // PI/2
|
||||||
|
private static final double MIN_LON = Math.toRadians(-180d); // -PI
|
||||||
|
private static final double MAX_LON = Math.toRadians(180d); // PI
|
||||||
|
|
||||||
|
public static DistanceBoundingCheck distanceBoundingCheck(double sourceLatitude, double sourceLongitude, double distance, DistanceUnit unit) {
|
||||||
|
// angular distance in radians on a great circle
|
||||||
|
double radDist = distance / unit.getEarthRadius();
|
||||||
|
|
||||||
|
double radLat = Math.toRadians(sourceLatitude);
|
||||||
|
double radLon = Math.toRadians(sourceLongitude);
|
||||||
|
|
||||||
|
double minLat = radLat - radDist;
|
||||||
|
double maxLat = radLat + radDist;
|
||||||
|
|
||||||
|
double minLon, maxLon;
|
||||||
|
if (minLat > MIN_LAT && maxLat < MAX_LAT) {
|
||||||
|
double deltaLon = Math.asin(Math.sin(radDist) / Math.cos(radLat));
|
||||||
|
minLon = radLon - deltaLon;
|
||||||
|
if (minLon < MIN_LON) minLon += 2d * Math.PI;
|
||||||
|
maxLon = radLon + deltaLon;
|
||||||
|
if (maxLon > MAX_LON) maxLon -= 2d * Math.PI;
|
||||||
|
} else {
|
||||||
|
// a pole is within the distance
|
||||||
|
minLat = Math.max(minLat, MIN_LAT);
|
||||||
|
maxLat = Math.min(maxLat, MAX_LAT);
|
||||||
|
minLon = MIN_LON;
|
||||||
|
maxLon = MAX_LON;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point left = new Point(Math.toDegrees(minLat), Math.toDegrees(minLon));
|
||||||
|
Point right = new Point(Math.toDegrees(maxLat), Math.toDegrees(maxLon));
|
||||||
|
if (minLon > maxLon) {
|
||||||
|
return new Meridian180DistanceBoundingCheck(left, right);
|
||||||
|
}
|
||||||
|
return new SimpleDistanceBoundingCheck(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
public static GeoDistance fromString(String s) {
|
public static GeoDistance fromString(String s) {
|
||||||
if ("plane".equals(s)) {
|
if ("plane".equals(s)) {
|
||||||
return PLANE;
|
return PLANE;
|
||||||
|
@ -117,6 +155,50 @@ public enum GeoDistance {
|
||||||
double calculate(double targetLatitude, double targetLongitude);
|
double calculate(double targetLatitude, double targetLongitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface DistanceBoundingCheck {
|
||||||
|
|
||||||
|
boolean isWithin(double targetLatitude, double targetLongitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AlwaysDistanceBoundingCheck ALWAYS_INSTANCE = new AlwaysDistanceBoundingCheck();
|
||||||
|
|
||||||
|
private static class AlwaysDistanceBoundingCheck implements DistanceBoundingCheck {
|
||||||
|
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Meridian180DistanceBoundingCheck implements DistanceBoundingCheck {
|
||||||
|
|
||||||
|
private final Point left;
|
||||||
|
private final Point right;
|
||||||
|
|
||||||
|
public Meridian180DistanceBoundingCheck(Point left, Point right) {
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||||
|
return (targetLatitude >= left.lat && targetLatitude <= right.lat) &&
|
||||||
|
(targetLongitude >= left.lon || targetLongitude <= right.lon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleDistanceBoundingCheck implements DistanceBoundingCheck {
|
||||||
|
private final Point left;
|
||||||
|
private final Point right;
|
||||||
|
|
||||||
|
public SimpleDistanceBoundingCheck(Point left, Point right) {
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||||
|
return (targetLatitude >= left.lat && targetLatitude <= right.lat) &&
|
||||||
|
(targetLongitude >= left.lon && targetLongitude <= right.lon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class PlaneFixedSourceDistance implements FixedSourceDistance {
|
public static class PlaneFixedSourceDistance implements FixedSourceDistance {
|
||||||
|
|
||||||
private final double sourceLatitude;
|
private final double sourceLatitude;
|
||||||
|
|
|
@ -48,8 +48,10 @@ public class GeoDistanceFilter extends Filter {
|
||||||
private final FieldDataCache fieldDataCache;
|
private final FieldDataCache fieldDataCache;
|
||||||
|
|
||||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||||
|
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||||
|
|
||||||
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache) {
|
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache,
|
||||||
|
boolean optimizeBbox) {
|
||||||
this.lat = lat;
|
this.lat = lat;
|
||||||
this.lon = lon;
|
this.lon = lon;
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
|
@ -58,6 +60,7 @@ public class GeoDistanceFilter extends Filter {
|
||||||
this.fieldDataCache = fieldDataCache;
|
this.fieldDataCache = fieldDataCache;
|
||||||
|
|
||||||
this.fixedSourceDistance = geoDistance.fixedSourceDistance(lat, lon, DistanceUnit.MILES);
|
this.fixedSourceDistance = geoDistance.fixedSourceDistance(lat, lon, DistanceUnit.MILES);
|
||||||
|
this.distanceBoundingCheck = optimizeBbox ? GeoDistance.distanceBoundingCheck(lat, lon, distance, DistanceUnit.MILES) : GeoDistance.ALWAYS_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double lat() {
|
public double lat() {
|
||||||
|
@ -82,7 +85,7 @@ public class GeoDistanceFilter extends Filter {
|
||||||
|
|
||||||
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
||||||
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
||||||
return new GeoDistanceDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distance);
|
return new GeoDistanceDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -120,11 +123,14 @@ public class GeoDistanceFilter extends Filter {
|
||||||
private final double distance; // in miles
|
private final double distance; // in miles
|
||||||
private final GeoPointFieldData fieldData;
|
private final GeoPointFieldData fieldData;
|
||||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||||
|
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||||
|
|
||||||
public GeoDistanceDocSet(int maxDoc, GeoPointFieldData fieldData, GeoDistance.FixedSourceDistance fixedSourceDistance, double distance) {
|
public GeoDistanceDocSet(int maxDoc, GeoPointFieldData fieldData, GeoDistance.FixedSourceDistance fixedSourceDistance, GeoDistance.DistanceBoundingCheck distanceBoundingCheck,
|
||||||
|
double distance) {
|
||||||
super(maxDoc);
|
super(maxDoc);
|
||||||
this.fieldData = fieldData;
|
this.fieldData = fieldData;
|
||||||
this.fixedSourceDistance = fixedSourceDistance;
|
this.fixedSourceDistance = fixedSourceDistance;
|
||||||
|
this.distanceBoundingCheck = distanceBoundingCheck;
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,16 +150,25 @@ public class GeoDistanceFilter extends Filter {
|
||||||
double[] lats = fieldData.latValues(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
double[] lons = fieldData.lonValues(doc);
|
double[] lons = fieldData.lonValues(doc);
|
||||||
for (int i = 0; i < lats.length; i++) {
|
for (int i = 0; i < lats.length; i++) {
|
||||||
double d = fixedSourceDistance.calculate(lats[i], lons[i]);
|
double lat = lats[i];
|
||||||
|
double lon = lons[i];
|
||||||
|
if (distanceBoundingCheck.isWithin(lat, lon)) {
|
||||||
|
double d = fixedSourceDistance.calculate(lat, lon);
|
||||||
if (d < distance) {
|
if (d < distance) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
double d = fixedSourceDistance.calculate(fieldData.latValue(doc), fieldData.lonValue(doc));
|
double lat = fieldData.latValue(doc);
|
||||||
|
double lon = fieldData.lonValue(doc);
|
||||||
|
if (distanceBoundingCheck.isWithin(lat, lon)) {
|
||||||
|
double d = fixedSourceDistance.calculate(lat, lon);
|
||||||
return d < distance;
|
return d < distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,14 @@ public class GeoDistanceRangeFilter extends Filter {
|
||||||
|
|
||||||
private final GeoDistance geoDistance;
|
private final GeoDistance geoDistance;
|
||||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||||
|
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||||
|
|
||||||
private final String fieldName;
|
private final String fieldName;
|
||||||
|
|
||||||
private final FieldDataCache fieldDataCache;
|
private final FieldDataCache fieldDataCache;
|
||||||
|
|
||||||
public GeoDistanceRangeFilter(double lat, double lon, Double lowerVal, Double upperVal, boolean includeLower, boolean includeUpper, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache) {
|
public GeoDistanceRangeFilter(double lat, double lon, Double lowerVal, Double upperVal, boolean includeLower, boolean includeUpper, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache,
|
||||||
|
boolean optimizeBbox) {
|
||||||
this.lat = lat;
|
this.lat = lat;
|
||||||
this.lon = lon;
|
this.lon = lon;
|
||||||
this.geoDistance = geoDistance;
|
this.geoDistance = geoDistance;
|
||||||
|
@ -71,7 +73,10 @@ public class GeoDistanceRangeFilter extends Filter {
|
||||||
inclusiveUpperPoint = NumericUtils.sortableLongToDouble(includeUpper ? i : (i - 1L));
|
inclusiveUpperPoint = NumericUtils.sortableLongToDouble(includeUpper ? i : (i - 1L));
|
||||||
} else {
|
} else {
|
||||||
inclusiveUpperPoint = Double.POSITIVE_INFINITY;
|
inclusiveUpperPoint = Double.POSITIVE_INFINITY;
|
||||||
|
optimizeBbox = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.distanceBoundingCheck = optimizeBbox ? GeoDistance.distanceBoundingCheck(lat, lon, inclusiveUpperPoint, DistanceUnit.MILES) : GeoDistance.ALWAYS_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double lat() {
|
public double lat() {
|
||||||
|
@ -92,7 +97,7 @@ public class GeoDistanceRangeFilter extends Filter {
|
||||||
|
|
||||||
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
||||||
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
||||||
return new GeoDistanceRangeDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, inclusiveLowerPoint, inclusiveUpperPoint);
|
return new GeoDistanceRangeDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, inclusiveLowerPoint, inclusiveUpperPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,13 +138,16 @@ public class GeoDistanceRangeFilter extends Filter {
|
||||||
|
|
||||||
private final GeoPointFieldData fieldData;
|
private final GeoPointFieldData fieldData;
|
||||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||||
|
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||||
private final double inclusiveLowerPoint; // in miles
|
private final double inclusiveLowerPoint; // in miles
|
||||||
private final double inclusiveUpperPoint; // in miles
|
private final double inclusiveUpperPoint; // in miles
|
||||||
|
|
||||||
public GeoDistanceRangeDocSet(int maxDoc, GeoPointFieldData fieldData, GeoDistance.FixedSourceDistance fixedSourceDistance, double inclusiveLowerPoint, double inclusiveUpperPoint) {
|
public GeoDistanceRangeDocSet(int maxDoc, GeoPointFieldData fieldData, GeoDistance.FixedSourceDistance fixedSourceDistance, GeoDistance.DistanceBoundingCheck distanceBoundingCheck,
|
||||||
|
double inclusiveLowerPoint, double inclusiveUpperPoint) {
|
||||||
super(maxDoc);
|
super(maxDoc);
|
||||||
this.fieldData = fieldData;
|
this.fieldData = fieldData;
|
||||||
this.fixedSourceDistance = fixedSourceDistance;
|
this.fixedSourceDistance = fixedSourceDistance;
|
||||||
|
this.distanceBoundingCheck = distanceBoundingCheck;
|
||||||
this.inclusiveLowerPoint = inclusiveLowerPoint;
|
this.inclusiveLowerPoint = inclusiveLowerPoint;
|
||||||
this.inclusiveUpperPoint = inclusiveUpperPoint;
|
this.inclusiveUpperPoint = inclusiveUpperPoint;
|
||||||
}
|
}
|
||||||
|
@ -160,17 +168,25 @@ public class GeoDistanceRangeFilter extends Filter {
|
||||||
double[] lats = fieldData.latValues(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
double[] lons = fieldData.lonValues(doc);
|
double[] lons = fieldData.lonValues(doc);
|
||||||
for (int i = 0; i < lats.length; i++) {
|
for (int i = 0; i < lats.length; i++) {
|
||||||
double d = fixedSourceDistance.calculate(lats[i], lons[i]);
|
double lat = lats[i];
|
||||||
|
double lon = lons[i];
|
||||||
|
if (distanceBoundingCheck.isWithin(lat, lon)) {
|
||||||
|
double d = fixedSourceDistance.calculate(lat, lon);
|
||||||
if (d >= inclusiveLowerPoint && d <= inclusiveUpperPoint) {
|
if (d >= inclusiveLowerPoint && d <= inclusiveUpperPoint) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
double d = fixedSourceDistance.calculate(fieldData.latValue(doc), fieldData.lonValue(doc));
|
double lat = fieldData.latValue(doc);
|
||||||
|
double lon = fieldData.lonValue(doc);
|
||||||
|
if (distanceBoundingCheck.isWithin(lat, lon)) {
|
||||||
|
double d = fixedSourceDistance.calculate(lat, lon);
|
||||||
if (d >= inclusiveLowerPoint && d <= inclusiveUpperPoint) {
|
if (d >= inclusiveLowerPoint && d <= inclusiveUpperPoint) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,17 +115,4 @@ public class GeoPolygonFilter extends Filter {
|
||||||
return inPoly;
|
return inPoly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Point {
|
|
||||||
public double lat;
|
|
||||||
public double lon;
|
|
||||||
|
|
||||||
public Point() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point(double lat, double lon) {
|
|
||||||
this.lat = lat;
|
|
||||||
this.lon = lon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search 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.index.search.geo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class Point {
|
||||||
|
public double lat;
|
||||||
|
public double lon;
|
||||||
|
|
||||||
|
public Point() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point(double lat, double lon) {
|
||||||
|
this.lat = lat;
|
||||||
|
this.lon = lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Point point = (Point) o;
|
||||||
|
|
||||||
|
if (Double.compare(point.lat, lat) != 0) return false;
|
||||||
|
if (Double.compare(point.lon, lon) != 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result;
|
||||||
|
long temp;
|
||||||
|
temp = lat != +0.0d ? Double.doubleToLongBits(lat) : 0L;
|
||||||
|
result = (int) (temp ^ (temp >>> 32));
|
||||||
|
temp = lon != +0.0d ? Double.doubleToLongBits(lon) : 0L;
|
||||||
|
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[" + lat + ", " + lon + "]";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search 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.index.search.geo;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public class GeoDistanceTests {
|
||||||
|
|
||||||
|
@Test public void testDistanceCheck() {
|
||||||
|
// Note, is within is an approximation, so, even though 0.52 is outside 50mi, we still get "true"
|
||||||
|
GeoDistance.DistanceBoundingCheck check = GeoDistance.distanceBoundingCheck(0, 0, 50, DistanceUnit.MILES);
|
||||||
|
//System.out.println("Dist: " + GeoDistance.ARC.calculate(0, 0, 0.5, 0.5, DistanceUnit.MILES));
|
||||||
|
assertThat(check.isWithin(0.5, 0.5), equalTo(true));
|
||||||
|
//System.out.println("Dist: " + GeoDistance.ARC.calculate(0, 0, 0.52, 0.52, DistanceUnit.MILES));
|
||||||
|
assertThat(check.isWithin(0.52, 0.52), equalTo(true));
|
||||||
|
//System.out.println("Dist: " + GeoDistance.ARC.calculate(0, 0, 1, 1, DistanceUnit.MILES));
|
||||||
|
assertThat(check.isWithin(1, 1), equalTo(false));
|
||||||
|
|
||||||
|
|
||||||
|
check = GeoDistance.distanceBoundingCheck(0, 179, 200, DistanceUnit.MILES);
|
||||||
|
//System.out.println("Dist: " + GeoDistance.ARC.calculate(0, 179, 0, -179, DistanceUnit.MILES));
|
||||||
|
assertThat(check.isWithin(0, -179), equalTo(true));
|
||||||
|
//System.out.println("Dist: " + GeoDistance.ARC.calculate(0, 179, 0, -178, DistanceUnit.MILES));
|
||||||
|
assertThat(check.isWithin(0, -178), equalTo(false));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue