[MYSQL] 지역 검색을 위한 폴리곤 기반 데이터베이스 설계 및 구현

세모네모동굴배이·2024년 10월 20일
1

이번 포스트에서는 MySQL과 Kotlin을 사용해 폴리곤 데이터를 기반으로 지역 검색을 구현한 과정을 공유하려 합니다. 핵심 목표는 다중 폴리곤(multipolygon) 데이터를 활용한 지역 기반의 지리적 검색을 처리하는 것으로, 공간 데이터 타입과 지리적 함수들을 사용하는 것이 주요 과제였습니다.

데이터베이스 설계

이 구현의 핵심은 AREA 테이블로, 상권 구역을 나타내는 COORDINATES 컬럼에 다중 폴리곤 데이터를 저장했습니다. 이를 통해 점-폴리곤 포함 여부(Point-in-Polygon)나 경계 상자를 이용한 검색(Bounding Box Search) 같은 공간 쿼리를 수행할 수 있습니다. 테이블 스키마는 다음과 같습니다:

CREATE TABLE `AREA` (
  `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '지역 아이디',
  `CITY_CODE` int(10) DEFAULT NULL COMMENT '시도코드',
  `CITY` varchar(100) DEFAULT NULL COMMENT '지역 이름',
  `DISTRICT` varchar(100) DEFAULT NULL COMMENT '구 이름',
  `TRADE_NAME` varchar(100) DEFAULT NULL COMMENT '상권이름',
  `COORDINATES` multipolygon DEFAULT NULL COMMENT '좌표',
  `CREATED_AT` datetime NOT NULL DEFAULT current_timestamp() COMMENT '생성일',
  `UPDATED_AT` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '수정일',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='지역 데이터 테이블';

여기서 COORDINATES 필드는 MySQL의 multipolygon 데이터 타입을 사용하여 복잡한 지역 경계를 저장합니다. 이를 활용해 MySQL의 내장 공간 함수인 ST_Contains와 ST_Intersects를 통해 폴리곤 기반 검색을 수행할 수 있었습니다.

주요 알고리즘 및 공간 쿼리

  1. 점-폴리곤 포함 여부(Point-in-Polygon) 검색: 특정 좌표(위도 및 경도)를 포함하는 상권 지역을 찾기 위해 ST_Contains 함수를 사용했습니다. 이 쿼리는 주어진 좌표가 COORDINATES 컬럼의 폴리곤 내부에 있는지 확인합니다.
@Query("""
    SELECT ... 
    FROM AreaEntity t 
    LEFT JOIN FloorEntity f ON t.id = f.areaId 
    WHERE ST_Contains(t.coordinates, ST_GeomFromText(:point)) = true
    AND t.city = :city AND t.district LIKE :district
""")
fun findByCoordinatesContaining(city: String, district: String, @Param("point") point: String): List<Map<String, Any>>
  1. 경계 상자를 활용한 검색(Bounding Box Search): 사각형 범위(경계 상자) 내에 겹치는 지역을 검색할 때는 ST_Intersects 함수를 사용했습니다. 이를 통해 해당 상자와 겹치는 모든 폴리곤을 찾아낼 수 있었습니다.
@Query("""
    SELECT ...
    FROM AreaEntity t 
    LEFT JOIN FloorEntity f ON t.id = f.areaId 
    WHERE ST_Intersects(t.coordinates, ST_GeomFromText(:boundingBox)) = true
""")
fun findByCoordinatesOverlappingBoundingBox(@Param("boundingBox") boundingBox: String): List<Map<String, Any>>

결론

MySQL의 지리적 기능과 Kotlin의 함수형 프로그래밍 기능을 활용하여 점-폴리곤 포함 여부(Point-in-Polygon)와 경계 상자 검색(Bounding Box Search) 모두를 처리할 수 있는 견고한 시스템을 구현했습니다. 이는 지역 기반 검색이 필요한 다양한 지리적 응용 프로그램에서 매우 유용하게 사용될 수 있습니다.

향후에는 폴리곤 데이터에 대한 인덱싱을 추가로 최적화하고, 더 복잡한 쿼리를 위한 다른 공간 함수들도 탐색해볼 계획입니다.

[FE] :

https://velog.io/@jong1co/FE-%ED%83%80%EC%9D%BC%EB%A7%81Tiling-%EA%B8%B0%EB%B2%95%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%A7%80%EB%8F%84-%EC%A1%B0%ED%9A%8C-API-%EC%BA%90%EC%8B%B1

post-custom-banner

0개의 댓글