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) {
|
MILES(3959, 24902) {
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return "miles";
|
return "miles";
|
||||||
}@Override public double toMiles(double distance) {
|
}
|
||||||
|
|
||||||
|
@Override public double toMiles(double distance) {
|
||||||
return distance;
|
return distance;
|
||||||
}@Override public double toKilometers(double distance) {
|
}
|
||||||
|
|
||||||
|
@Override public double toKilometers(double distance) {
|
||||||
return distance * MILES_KILOMETRES_RATIO;
|
return distance * MILES_KILOMETRES_RATIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString(double distance) {
|
@Override public String toString(double distance) {
|
||||||
return distance + "mi";
|
return distance + "mi";
|
||||||
}},
|
}
|
||||||
|
},
|
||||||
KILOMETERS(6371, 40076) {
|
KILOMETERS(6371, 40076) {
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return "km";
|
return "km";
|
||||||
}@Override public double toMiles(double distance) {
|
}
|
||||||
|
|
||||||
|
@Override public double toMiles(double distance) {
|
||||||
return distance / MILES_KILOMETRES_RATIO;
|
return distance / MILES_KILOMETRES_RATIO;
|
||||||
}@Override public double toKilometers(double distance) {
|
}
|
||||||
|
|
||||||
|
@Override public double toKilometers(double distance) {
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString(double distance) {
|
@Override public String toString(double distance) {
|
||||||
return distance + "km";
|
return distance + "km";
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static final double MILES_KILOMETRES_RATIO = 1.609344;
|
static final double MILES_KILOMETRES_RATIO = 1.609344;
|
||||||
|
|
||||||
|
@ -95,10 +107,24 @@ public enum DistanceUnit {
|
||||||
|
|
||||||
protected final double earthCircumference;
|
protected final double earthCircumference;
|
||||||
protected final double earthRadius;
|
protected final double earthRadius;
|
||||||
|
protected final double distancePerDegree;
|
||||||
|
|
||||||
DistanceUnit(double earthRadius, double earthCircumference) {
|
DistanceUnit(double earthRadius, double earthCircumference) {
|
||||||
this.earthCircumference = earthCircumference;
|
this.earthCircumference = earthCircumference;
|
||||||
this.earthRadius = earthRadius;
|
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);
|
public abstract double toMiles(double distance);
|
||||||
|
|
|
@ -39,6 +39,18 @@ public class GeoPointDocFieldData extends DocFieldData<GeoPointFieldData> {
|
||||||
return fieldData.values(docId);
|
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) {
|
public double distance(double lat, double lon) {
|
||||||
return fieldData.distance(docId, DistanceUnit.MILES, lat, 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);
|
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) {
|
public double distanceGeohash(int docId, DistanceUnit unit, String geoHash) {
|
||||||
GeoPointHash geoPointHash = geoHashCache.get().get();
|
GeoPointHash geoPointHash = geoHashCache.get().get();
|
||||||
if (geoPointHash.geoHash != geoHash) {
|
if (geoPointHash.geoHash != geoHash) {
|
||||||
|
|
|
@ -154,6 +154,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
||||||
} else {
|
} else {
|
||||||
distance = DistanceUnit.parse((String) vDistance, unit, DistanceUnit.MILES);
|
distance = DistanceUnit.parse((String) vDistance, unit, DistanceUnit.MILES);
|
||||||
}
|
}
|
||||||
|
distance = geoDistance.normalize(distance, DistanceUnit.MILES);
|
||||||
|
|
||||||
MapperService mapperService = parseContext.mapperService();
|
MapperService mapperService = parseContext.mapperService();
|
||||||
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
|
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
|
||||||
|
|
|
@ -205,11 +205,13 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
||||||
} else {
|
} else {
|
||||||
from = DistanceUnit.parse((String) vFrom, unit, DistanceUnit.MILES);
|
from = DistanceUnit.parse((String) vFrom, unit, DistanceUnit.MILES);
|
||||||
}
|
}
|
||||||
|
from = geoDistance.normalize(from, DistanceUnit.MILES);
|
||||||
if (vTo instanceof Number) {
|
if (vTo instanceof Number) {
|
||||||
to = unit.toMiles(((Number) vTo).doubleValue());
|
to = unit.toMiles(((Number) vTo).doubleValue());
|
||||||
} else {
|
} else {
|
||||||
to = DistanceUnit.parse((String) vTo, unit, DistanceUnit.MILES);
|
to = DistanceUnit.parse((String) vTo, unit, DistanceUnit.MILES);
|
||||||
}
|
}
|
||||||
|
to = geoDistance.normalize(to, DistanceUnit.MILES);
|
||||||
|
|
||||||
MapperService mapperService = parseContext.mapperService();
|
MapperService mapperService = parseContext.mapperService();
|
||||||
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
|
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}.
|
* Calculates distance as points on a plane. Faster, but less accurate than {@link #ARC}.
|
||||||
*/
|
*/
|
||||||
PLANE() {
|
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) {
|
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
||||||
double px = targetLongitude - sourceLongitude;
|
double px = targetLongitude - sourceLongitude;
|
||||||
double py = targetLatitude - sourceLatitude;
|
double py = targetLatitude - sourceLatitude;
|
||||||
double distanceMiles = Math.sqrt(px * px + py * py) * DISTANCE_PER_DEGREE;
|
return Math.sqrt(px * px + py * py) * unit.getDistancePerDegree();
|
||||||
return DistanceUnit.convert(distanceMiles, DistanceUnit.MILES, unit);
|
}
|
||||||
|
|
||||||
|
@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() {
|
ARC() {
|
||||||
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
@Override public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
|
||||||
LatLng sourcePoint = new LatLng(sourceLatitude, sourceLongitude);
|
// TODO: we might want to normalize longitude as we did in LatLng...
|
||||||
LatLng targetPoint = new LatLng(targetLatitude, targetLongitude);
|
double longitudeDifference = targetLongitude - sourceLongitude;
|
||||||
return DistanceUnit.convert(sourcePoint.arcDistance(targetPoint, DistanceUnit.MILES), DistanceUnit.MILES, unit);
|
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);
|
public abstract double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit);
|
||||||
|
|
||||||
|
@ -59,6 +92,8 @@ public enum GeoDistance {
|
||||||
return PLANE;
|
return PLANE;
|
||||||
} else if ("arc".equals(s)) {
|
} else if ("arc".equals(s)) {
|
||||||
return ARC;
|
return ARC;
|
||||||
|
} else if ("factor".equals(s)) {
|
||||||
|
return FACTOR;
|
||||||
}
|
}
|
||||||
throw new ElasticSearchIllegalArgumentException("No geo distance for [" + s + "]");
|
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.action.search.SearchResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.index.search.geo.GeoDistance;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.sort.SortBuilders;
|
import org.elasticsearch.search.sort.SortBuilders;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
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")));
|
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
|
searchResponse = client.prepareSearch() // from NY
|
||||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("2km").point(40.7143528, -74.0059731)))
|
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("2km").point(40.7143528, -74.0059731)))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
Loading…
Reference in New Issue