참조
http://www.elastic.co/guide/en/elasticsearch/reference/1.5/search-facets-geo-distance-facet.html
elasticsearch에는 거리를 측정할 수 있는 API가 존재한다. 위 경도를 GeoDistance 클래스를 이용해서 거리를 측정할 수 있다. SLOPPY_ARC 측정하는 것이 elasticsearch에서는 디폴트로 쓰이고 있다.
어중간한 라이브러리 보다는 거리 측정 API로는 elasticsearch로 쓰니 좋았다.
double distance = GeoDistance.SLOPPY_ARC.calculate(srcLatitude, srcLongitude, targetLatitude, targetLongitude, DistanceUnit.METERS);
double distance = GeoDistance.ARC.calculate(srcLatitude, srcLongitude, targetLatitude, targetLongitude, DistanceUnit.METERS);
double distance = GeoDistance.PLANE.calculate(srcLatitude, srcLongitude, targetLatitude, targetLongitude, DistanceUnit.METERS);
arc는 지구(구) 기준으로 정말 실제 거리를 측정한다. 따라서 속도가 이 셋 중에 느리지만, 정확도 높다.
slooppy_arc는 정확도는 arc에 비해 조금 떨어지지만, 속도가 arc보다 빠르다.
plane은 그냥 지도에서 잰다. 속도가 가장 빠르지만, 실제 거리가 맞지 않는다.
테스트를 해보니 가까운 거리(1km 이내) 에서는 plane으로 측정하는 의미있을 수 있다. 먼 거리(1km이상)에서는 잘못된 측정이 될 수 있다. arc에서 7km가 나왔는데. plane에서는 11km가 나온다.
/**
* Calculates distance factor.
*/
FACTOR() {
@Override
public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
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());
}
@Override
public FixedSourceDistance fixedSourceDistance(double sourceLatitude, double sourceLongitude, DistanceUnit unit) {
return new FactorFixedSourceDistance(sourceLatitude, sourceLongitude, unit);
}
},
/**
* Calculates distance as points on a globe.
*/
ARC() {
@Override
public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
double x1 = sourceLatitude * Math.PI / 180D;
double x2 = targetLatitude * Math.PI / 180D;
double h1 = 1D - Math.cos(x1 - x2);
double h2 = 1D - Math.cos((sourceLongitude - targetLongitude) * Math.PI / 180D);
double h = (h1 + Math.cos(x1) * Math.cos(x2) * h2) / 2;
double averageLatitude = (x1 + x2) / 2;
double diameter = GeoUtils.earthDiameter(averageLatitude);
return unit.fromMeters(diameter * Math.asin(Math.min(1, Math.sqrt(h))));
}
@Override
public double normalize(double distance, DistanceUnit unit) {
return distance;
}
@Override
public FixedSourceDistance fixedSourceDistance(double sourceLatitude, double sourceLongitude, DistanceUnit unit) {
return new ArcFixedSourceDistance(sourceLatitude, sourceLongitude, unit);
}
},
/**
* Calculates distance as points on a globe in a sloppy way. Close to the pole areas the accuracy
* of this function decreases.
*/
SLOPPY_ARC() {
@Override
public double normalize(double distance, DistanceUnit unit) {
return distance;
}
@Override
public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
return unit.fromMeters(SloppyMath.haversin(sourceLatitude, sourceLongitude, targetLatitude, targetLongitude) * 1000.0);
}
@Override
public FixedSourceDistance fixedSourceDistance(double sourceLatitude, double sourceLongitude, DistanceUnit unit) {
return new SloppyArcFixedSourceDistance(sourceLatitude, sourceLongitude, unit);
}
};
/**
* Default {@link GeoDistance} function. This method should be used, If no specific function has been selected.
* This is an alias for <code>SLOPPY_ARC</code>
*/
public static final GeoDistance DEFAULT = SLOPPY_ARC;
'Elasticsearch' 카테고리의 다른 글
[elasticsearch] shard, replica 개념 (0) | 2015.05.22 |
---|---|
[elasticsearch] index(색인) 이름 허용 글자 (0) | 2015.05.22 |
elasticsearch의 geo distance filter 의 결과는 caching하지 않는다.(디폴트) (0) | 2015.05.06 |
ElasticsearchIntegrationTest 상속하여 @SuiteScopeTest - setupSuiteScopeCluster() 사용 (0) | 2015.05.06 |
elasticsearch intergration test 시 ClusterScope 주의사항 (0) | 2015.05.06 |