참조 

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가 나온다. 


https://github.com/elastic/elasticsearch/blob/master/src/main/java/org/elasticsearch/common/geo/GeoDistance.java



    /**

     * 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; 



Posted by '김용환'
,