공간 데이터와 MySQL을 활용한 추억의 장소 탐색

김현재·2024년 8월 2일
post-thumbnail

✨배경 지식

공간 데이터란?

요즘 프로젝트에서 공간 데이터를 다룰 일이 있어서 어떤 식으로 다뤄야할지 고민이 많다.

공간 데이터는 좌표계를 통한 지리적인 위치 데이터를 의미한다. 좌표계라는 단위는 위도 경도로 나타나는 일반적인 좌표계중 하나이다.
좌표계는 지구 상의 특정 위치를 정확하게 나타내기 위해 사용되는 시스템으로, 각각의 목적에 따라 여러 종류가 존재한다. 그 중에서 나는 가장 일반적으로 사용되는 위도/경도 좌표계를 사용하는 공간 데이터를 다룰 것이다.

용어 설명

  • OGC: 위치 기반 데이터에 대한 표준을 수립하는 단체이다.
  • OpenGIS: WKT나 WKB 같은 지리 정보 데이터를 표기하는 방법과 저장하는 방법, 그리고 SRID와 같은 표준을 포함한다.
  • SRS: 공간 참조 시스템, 좌표계라고 생각하면 된다.
    • GCS(지리 좌표계): 지구 구체상의 특정 위치나 공간을 표현하는 좌표계를 의미한다. 위도와 경도와 같이 각도 단위의 숫자로 표시된다.
    • PCS(투영 좌표계): 구체 형태의 지구를 종이 지도와 같은 평면으로 투영시킨 좌표계다. PCS는 GCS 위치 데이터를 2차원 평면인 종이에 어떻게 표현할지를 정의한다.
    • 동일 지점이라도 좌표계에 따라 표시 방법이 달라진다. 같은 위, 경도 좌표라 해도 참고하는 공간 좌표계가 달라지면 실제 위치는 달라진다. 따라서 주의할 필요가 있다.
    • Real MySQL 책에서는 SRS 는 좌표계, GCS는 지리 좌표계(구면 좌표계), PCS는 투영 좌표계라고 줄여 부를 수 있다.
  • WKT와 WKB: WKT는 사람 눈으로 확인 가능한 텍스트 포맷이며, WKB는 컴퓨터에 저장할 수 있는 형태의 저장 표준이다. MySQL 서버가 내부적으로 사용하는 이진 데이터 포맷은 WKB 포맷과 흡사하지만 완전 동일하지는 않다.

SRS는 SRS_ID로 고유 번호로 표현되고 이를 이용해서 SRS 를 구분한다. 이것에 따라 같은 위치라도 정의가 달라지기 때문에 반드시 이를 인식하고 있어야한다. WGS84는 지구 전체를 구체 형태로 표시하기 때문에 지리 좌표계이다. 이는 4326으로 표현할 수 있다. 이에 대한 단위는 degree이다. ST_SPATIAL_REFERENCE_SYSTEMS에 잘 저장되어 있다.

MySQL에는 투영좌표계나 지리 좌표계에 평면 좌표계가 있다. 평면 좌표계에서는 SRID=0 인 좌표계로 표현되며 단위를 가지지 않고 X,Y 축이 제한이 없다. X축 Y축 단위를 m 로 표현하면 SRID=3857인 투영 좌표계가 된다.

MySQL8.0 부터는 SRID를 지원하기 때문에 SRID에 대해서 명시적으로 지정하지 않을시 0으로 인식 되기 때문에 실제 구면상의 거리를 계산하는 것이 아닌 단위가 없는 평면 좌표계에서 계산하게 된다.

결과적으로 실제로 존재하는 지구상의 위치 데이터를 표현하는 것이 우리의 목표 이기 때문에 우리는 WGS84(4326)으로 지구를 표현하기로 마음 먹었다.

공간 데이터 타입

MySQL에서 제공하는 공간 데이터의 종류는 총 7가지이다. 단일 타입으로는 Point, LineString, Polygon 세 가지가 있다. 나머지 타입들은 이 세 가지 타입의 조합이다.

  • Point : 좌표 공간의 한 지점
  • LineString: 다수의 Point를 연결해 주는 선분
  • Polygon: 다수의 선분이 연결되어 닫힌 상태

각각의 컬럼에는 당연하게도 알맞은 데이터 타입만 입력할 수 있지만, geometry 타입에는 모든 공간 데이터 타입의 저장이 가능한 슈퍼 타입이다.

RTree 알고리즘

MBR 이란?

Minimum Bounding Rectangle의 약자로 해당 도형을 감싸는 최소 크기의 사각형을 의미한다. 이 사각형들의 포함관계를 B-Tree 형태로 구현한 인덱스가 R-Tree 인덱스이다.

일반적으로 WGS84 기준의 위도, 경도 좌표 저장에 주로 사용된다. R-Tree 인덱스의 경우 각 도형의 포함 관계를 이용해 만들어진 인덱스다. 따라서 ST_Contains 혹은 ST_Within()등 과 같은 포함관계를 비교하는 함수로 검색을 수행하는 경우에만 인덱스를 이용할 수 있다.




프로젝트 적용

구상

공간 데이터들은 공간 함수를 통해 활용할 수 있다. 현재 내가 구현해야하는 기능은 현재 위치를 기준으로 일정 반경 내에 있는 추억의 장소 데이터들을 찾아 내는 기능이다.

앞서 ST_DISTANCE를 사용할 시 올바르게 인덱스를 사용할 수 없다는 사실을 책에서 확인했었다.
따라서 위에서 언급한 R-Tree 인덱스 용도를 사용하기 위해서 ST_Contains 혹은 ST_Within()등 과 같은 포함관계를 비교하는 함수를 사용하는 편이 좋은 퍼포먼스를 낼 수 있을 거라 느꼈다.

위의 그림 처럼 일정 반경을 기준으로 그림을 그려줄 필요가 있었는데, 범위를 나타내는 반경 사각 박스를 어떤식으로 그릴지에 대해 고민을 할 필요가 있었다. 처음에는 ST_MakeEnvelope를 활용하려고 했으나 제대로 검색이 되지 않았다.

그 후로 다른 함수를 찾아보던 중 ST_BUFFER이라는 함수가 있다는 것을 알게되었고 이를 사용하기로 했다.

구현 내용

SELECT
    *,
    ST_Distance(POINT_COLUMN, ST_GeomFromText('POINT(-73.985656 40.748817)', 4326)) AS distance
FROM
    테이블 이름
WHERE
    ST_Within(
        POINT_COLUMN,
        ST_Buffer(
            ST_GeomFromText('POINT(-73.985656 40.748817)', 4326),
            100
        )
    )
    AND member_id IN (1, 2);
  • ST_DISTANCE: 제대로 거리내의 지도를 가져오는지 확인하기 위해 거리 계산을 하는 함수를 활용하였다.
  • ST_GeomFromText: WKT 문자열을 Geometry 타입으로 변환하는 함수이다. SRID를 통해 우리가 활용하는 WGS84 좌표계를 활용하겠다고 지정해줄 수 있다.
  • ST_BUFFER: g1에서 d 거리만큼 확장된 공간 객체를 반환한다

ST_BUFFER같은 경우에는 hibernate 공식 홈페이지 참고 결과 hibernate 구현체로 사용할 수 없다는 사실을 알 수 있었다. 따라서 mysql native 쿼리를 사용하는 것으로 선택을 했다.

결과

그 결과 올바르게 검색이 되는지를 확인할 수 있었다.



느낀점

공간 데이터에 대해서 너무 나이브하게 생각한 느낌이 강했다. Point 에 대한 검색을 하려니 생각보다 변수가 많았다.

공간 데이터를 정확하게 이해하기 위해서는

  • 좌표계에 대한 이해
  • 좌표계를 표현할 수 있는 WKT에 대한 이해
  • 좌표계를 효율적으로 검색하기 위한 R-Tree 에 대한 이해
  • hibernate가 공간 인덱스

가 크게 필요한 것 같았다.

이러한 이해를 바탕으로 접근한다면 효율적으로 공간 데이터에 대한 이해를 할 수 있을 것 같다.

출처

https://tecoble.techcourse.co.kr/post/2023-10-04-spatial-data/

Real MySQL

hibernate 공식홈페이지

https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html

0개의 댓글