add an option to just compute distance factor
This commit is contained in:
parent
fcaa0e3261
commit
d371619dd8
|
@ -32,25 +32,37 @@ public enum DistanceUnit {
|
|||
MILES(3959, 24902) {
|
||||
@Override public String toString() {
|
||||
return "miles";
|
||||
}@Override public double toMiles(double distance) {
|
||||
}
|
||||
|
||||
@Override public double toMiles(double distance) {
|
||||
return distance;
|
||||
}@Override public double toKilometers(double distance) {
|
||||
}
|
||||
|
||||
@Override public double toKilometers(double distance) {
|
||||
return distance * MILES_KILOMETRES_RATIO;
|
||||
}
|
||||
|
||||
@Override public String toString(double distance) {
|
||||
return distance + "mi";
|
||||
}},
|
||||
}
|
||||
},
|
||||
KILOMETERS(6371, 40076) {
|
||||
@Override public String toString() {
|
||||
return "km";
|
||||
}@Override public double toMiles(double distance) {
|
||||
}
|
||||
|
||||
@Override public double toMiles(double distance) {
|
||||
return distance / MILES_KILOMETRES_RATIO;
|
||||
}@Override public double toKilometers(double distance) {
|
||||
}
|
||||
|
||||
@Override public double toKilometers(double distance) {
|
||||
return distance;
|
||||
}
|
||||
|
||||
@Override public String toString(double distance) {
|
||||
return distance + "km";
|
||||
}};
|
||||
}
|
||||
};
|
||||
|
||||
static final double MILES_KILOMETRES_RATIO = 1.609344;
|
||||
|
||||
|
@ -95,10 +107,24 @@ public enum DistanceUnit {
|
|||
|
||||
protected final double earthCircumference;
|
||||
protected final double earthRadius;
|
||||
protected final double distancePerDegree;
|
||||
|
||||
DistanceUnit(double earthRadius, double earthCircumference) {
|
||||
this.earthCircumference = earthCircumference;
|
||||
this.earthRadius = earthRadius;
|
||||
this.distancePerDegree = earthCircumference / 360;
|
||||
}
|
||||
|
||||
public double getEarthCircumference() {
|
||||
return earthCircumference;
|
||||
}
|
||||
|
||||
public double getEarthRadius() {
|
||||
return earthRadius;
|
||||
}
|
||||
|
||||
public double getDistancePerDegree() {
|
||||
return distancePerDegree;
|
||||
}
|
||||
|
||||
public abstract double toMiles(double distance);
|
||||
|
|
|
@ -39,6 +39,18 @@ public class GeoPointDocFieldData extends DocFieldData<GeoPointFieldData> {
|
|||
return fieldData.values(docId);
|
||||
}
|
||||
|
||||
public double factorDistance(double lat, double lon) {
|
||||
return fieldData.factorDistance(docId, DistanceUnit.MILES, lat, lon);
|
||||
}
|
||||
|
||||
public double arcDistance(double lat, double lon) {
|
||||
return fieldData.arcDistance(docId, DistanceUnit.MILES, lat, lon);
|
||||
}
|
||||
|
||||
public double arcDistanceInKm(double lat, double lon) {
|
||||
return fieldData.arcDistance(docId, DistanceUnit.KILOMETERS, lat, lon);
|
||||
}
|
||||
|
||||
public double distance(double lat, double lon) {
|
||||
return fieldData.distance(docId, DistanceUnit.MILES, lat, lon);
|
||||
}
|
||||
|
|
|
@ -82,6 +82,14 @@ public abstract class GeoPointFieldData extends FieldData<GeoPointDocFieldData>
|
|||
return GeoDistance.PLANE.calculate(latValue(docId), lonValue(docId), lat, lon, unit);
|
||||
}
|
||||
|
||||
public double arcDistance(int docId, DistanceUnit unit, double lat, double lon) {
|
||||
return GeoDistance.ARC.calculate(latValue(docId), lonValue(docId), lat, lon, unit);
|
||||
}
|
||||
|
||||
public double factorDistance(int docId, DistanceUnit unit, double lat, double lon) {
|
||||
return GeoDistance.FACTOR.calculate(latValue(docId), lonValue(docId), lat, lon, unit);
|
||||
}
|
||||
|
||||
public double distanceGeohash(int docId, DistanceUnit unit, String geoHash) {
|
||||
GeoPointHash geoPointHash = geoHashCache.get().get();
|
||||
if (geoPointHash.geoHash != geoHash) {
|
||||
|
|
|
@ -154,6 +154,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
|||
} else {
|
||||
distance = DistanceUnit.parse((String) vDistance, unit, DistanceUnit.MILES);
|
||||
}
|
||||
distance = geoDistance.normalize(distance, DistanceUnit.MILES);
|
||||
|
||||
MapperService mapperService = parseContext.mapperService();
|
||||
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
|
||||
|
|
|
@ -205,11 +205,13 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
|||
} else {
|
||||
from = DistanceUnit.parse((String) vFrom, unit, DistanceUnit.MILES);
|
||||
}
|
||||
from = geoDistance.normalize(from, DistanceUnit.MILES);
|
||||
if (vTo instanceof Number) {
|
||||
to = unit.toMiles(((Number) vTo).doubleValue());
|
||||
} else {
|
||||
to = DistanceUnit.parse((String) vTo, unit, DistanceUnit.MILES);
|
||||
}
|
||||
to = geoDistance.normalize(to, DistanceUnit.MILES);
|
||||
|
||||
MapperService mapperService = parseContext.mapperService();
|
||||
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
|
||||
|
|
|
@ -32,14 +32,30 @@ public enum GeoDistance {
|
|||
* Calculates distance as points on a plane. Faster, but less accurate than {@link #ARC}.
|
||||
*/
|
||||
PLANE() {
|
||||
private final static double EARTH_CIRCUMFERENCE_MILES = 24901;
|
||||
private final static double DISTANCE_PER_DEGREE = EARTH_CIRCUMFERENCE_MILES / 360;
|
||||
|
||||
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
||||
double px = targetLongitude - sourceLongitude;
|
||||
double py = targetLatitude - sourceLatitude;
|
||||
double distanceMiles = Math.sqrt(px * px + py * py) * DISTANCE_PER_DEGREE;
|
||||
return DistanceUnit.convert(distanceMiles, DistanceUnit.MILES, unit);
|
||||
return Math.sqrt(px * px + py * py) * unit.getDistancePerDegree();
|
||||
}
|
||||
|
||||
@Override public double normalize(double distance, DistanceUnit unit) {
|
||||
return distance;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Calculates distance factor.
|
||||
*/
|
||||
FACTOR() {
|
||||
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
||||
// TODO: we might want to normalize longitude as we did in LatLng...
|
||||
double longitudeDifference = targetLongitude - sourceLongitude;
|
||||
double a = Math.toRadians(90D - sourceLatitude);
|
||||
double c = Math.toRadians(90D - targetLatitude);
|
||||
return (Math.cos(a) * Math.cos(c)) + (Math.sin(a) * Math.sin(c) * Math.cos(Math.toRadians(longitudeDifference)));
|
||||
}
|
||||
|
||||
@Override public double normalize(double distance, DistanceUnit unit) {
|
||||
return Math.cos(distance / unit.getEarthRadius());
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -47,10 +63,27 @@ public enum GeoDistance {
|
|||
*/
|
||||
ARC() {
|
||||
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
||||
LatLng sourcePoint = new LatLng(sourceLatitude, sourceLongitude);
|
||||
LatLng targetPoint = new LatLng(targetLatitude, targetLongitude);
|
||||
return DistanceUnit.convert(sourcePoint.arcDistance(targetPoint, DistanceUnit.MILES), DistanceUnit.MILES, unit);
|
||||
}};
|
||||
// TODO: we might want to normalize longitude as we did in LatLng...
|
||||
double longitudeDifference = targetLongitude - sourceLongitude;
|
||||
double a = Math.toRadians(90D - sourceLatitude);
|
||||
double c = Math.toRadians(90D - targetLatitude);
|
||||
double factor = (Math.cos(a) * Math.cos(c)) + (Math.sin(a) * Math.sin(c) * Math.cos(Math.toRadians(longitudeDifference)));
|
||||
|
||||
if (factor < -1D) {
|
||||
return Math.PI * unit.getEarthRadius();
|
||||
} else if (factor >= 1D) {
|
||||
return 0;
|
||||
} else {
|
||||
return Math.acos(factor) * unit.getEarthRadius();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public double normalize(double distance, DistanceUnit unit) {
|
||||
return distance;
|
||||
}
|
||||
};
|
||||
|
||||
public abstract double normalize(double distance, DistanceUnit unit);
|
||||
|
||||
public abstract double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit);
|
||||
|
||||
|
@ -59,6 +92,8 @@ public enum GeoDistance {
|
|||
return PLANE;
|
||||
} else if ("arc".equals(s)) {
|
||||
return ARC;
|
||||
} else if ("factor".equals(s)) {
|
||||
return FACTOR;
|
||||
}
|
||||
throw new ElasticSearchIllegalArgumentException("No geo distance for [" + s + "]");
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.test.integration.search.geo;
|
|||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.search.geo.GeoDistance;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
|
@ -122,6 +123,18 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6")));
|
||||
}
|
||||
|
||||
// now with a PLANE type
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("3km").geoDistance(GeoDistance.PLANE).point(40.7143528, -74.0059731)))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(5l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(5));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6")));
|
||||
}
|
||||
|
||||
// factor type is really too small for this resolution
|
||||
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("2km").point(40.7143528, -74.0059731)))
|
||||
.execute().actionGet();
|
||||
|
|
Loading…
Reference in New Issue