Python/Django

[Django, DB] haversine 두 지점의 거리 Django Func 사용하기

yubi5050 2024. 6. 30. 16:06

두 지점의 거리 구하기 공식 - haversine

하버사인 공식(Haversine Formula) 공식은 구위의 두 점 사이의 거리를 경도와 위도를 고려하여 계산하는 공식

 

지도 맵 서비스 등에서 두 지점 간 거리를 재는데 사용 가능하다. 

아래 그림의 P와 Q사이의 거리를 계산해준다. 

 

https://en.wikipedia.org/wiki/Haversine_formula

 

 

haversine - PostgreSQL, MySQL

DB에 맞춰 사소한 문법 등은 달라 질 수 있다.  

만약 MySQL을 사용한다면, 기존에 내제되어 있는 Point 필드 등을 사용한 거리 계산도 가능하다. 

-- 두 위경도 사이의 거리 계산
CREATE OR REPLACE FUNCTION haversine(
    lat1 numeric,
    lon1 numeric,
    lat2 numeric,
    lon2 numeric
) RETURNS numeric AS $$
DECLARE
    R numeric = 6371000; -- 지구의 반지름 (미터)
    dlat numeric = RADIANS(lat2 - lat1);
    dlon numeric = RADIANS(lon2 - lon1);
    a numeric = SIN(dlat / 2) * SIN(dlat / 2) + COS(RADIANS(lat1)) * COS(RADIANS(lat2)) * SIN(dlon / 2) * SIN(dlon / 2);
    c numeric = 2 * ATAN2(SQRT(a), SQRT(1 - a));
BEGIN
    RETURN R * c / 1000;
END;
$$ LANGUAGE plpgsql;

 

 

django ORM 에서  사용시 db Func 사용

1. DB Custom 함수 등록 완료 (함수명 - haversine)

2. class Haversine 함수 선언 (함수명 - haversine)

3. annotate 등으로 만들어서 필드 접근

from django.db.models import Func

# Haverinse 함수 선언 - DB Custom 함수로 등록이 선행되어져야 함
class Haversine(Func):
    function = "haversine"
    template = "haversine(%(expressions)s)"
    output_field = FloatField()
    
# 객체에서 annotation으로 호출
A_annotation_dict = {
        # 두 위 경도 간 거리 - DB Func
        "haversine_distance": ExpressionWrapper(
        Haversine(
            F("latitude"),
            F("longitude"),
            standard_point[0],  # latitude
            standard_point[1],  # longitude
        ),
        output_field=FloatField(),
    ),
}

# 최종 결과 Queryset
results = A.objects.annotate(**A_annotation_dict)
resutls.haversine_distance # 17.157181 km