PostgreSQL Cube-Based Earth Distances와 Spring Data JPA Native Query를 이용하여
Spring Boot의 사용자 근처 가맹점 찾기 API를 구현하는 내용을 담았습니다
재난지원금 사용을 위해 경기도 지역화폐 웹서비스를 개발하면서
나의 위치 기준에서 몇 Km 내에 있는 OO시의 가맹점을 조회해주는 기능이 필요하였다
(재난지원금 정책상 자신이 거주하는 시 내에서만 사용가능하다)
사용중인 PostgreSQL에 추가 모듈인 earthdistance가 있는 것을 보았고
이 모듈과 함께 Spring Data JPA의 Native Query를 이용하여 구현하기로 결정하였다.
먼저 PostgreSQL의 earthdistance가 무엇이고 어떻게 사용하는지 알아보자
earthdistance
모듈은 2가지의 방법으로 거리 측정을 제공한다
cube
모듈을 이용한 Cube-Based
와 point
데이터 타입을 이용한 Point-Based
가 있다
- Cube-Based Earth Distances
- cube 모듈을 이용
- 사용을 위해 earthdistance 설치가 요구됨
- Point-Based Earth Distance
- 내장 point 데이터타입을 이용
주의할 점으로 earthdistance 모듈은 지구를 완벽한 구의 형태로 본다
따라서 문서에서는 해당 모듈이 부정확하다고 생각되면 PostGIS를 보라고 기재해두고 있다
지구는 타원의 형태를 띄고 있다.
따라서 경도 1도마다의 거리가 모두 다르다
이러한 지구의 거리를 계산하는 방법에 마침 좋은 세미나가 있다
이 글에서는 Cube-Based Earth Distance 방법을 이용해 구현해본다
먼저 psql로 DB서버에 접속하여 extension을 설치한다
필요한 extension은 cube
와 earthdistance
이다
roharon-db=# create extension cube;
CREATE EXTENSION
roharon-db=# create extension earthdistance;
CREATE EXTENSION
Cube-Based Earthdistance의 함수는 다음과 같다.
JPA를 사용하여 작성하기 전,
earth_distance(earth, earth)
와 ll_to_earth(float8, float8)
함수를 psql에서 쿼리를 사용해본다
가맹점 데이터가 담긴 store 테이블은 아래와 같이 구성되어있다.
Table "public.store"
Column | Type | Collation | Nullable | Default
--------------+------------------------+-----------+----------+---------
id | bigint | | not null |
address | character varying(255) | | |
big_category | character varying(255) | | |
category | character varying(500) | | |
latitude | real | | |
longitude | real | | |
phone_number | character varying(255) | | |
post_code | character varying(255) | | |
sigoon | character varying(255) | | |
title | character varying(500) | | not null |
update_date | character varying(255) | | |
Indexes:
"store_pkey" PRIMARY KEY, btree (id)
현 위치는 판교역 부근의 위치(37.394968, 127.111064)로 가정하고
1Km 이내의 가맹점을 조회한다면 아래와 같이 작성할 수 있다.
select * from store s where earth_distance(ll_to_earth(37.394968, 127.111064), ll_to_earth(s.latitude, s.longitude)) < 1000;
위 쿼리의 결과가 정상적으로 나왔다.
earthdistance 모듈을 사용하여 쿼리를 사용해봤으니 직접 JPA에 적용해보자
Native Query는 아래처럼 @Query 어노테이션에서 nativeQuery = true
로 두고
value 파라미터에 쿼리를 작성하면 된다.
@Query(value = "SELECT * FROM store s WHERE earth_distance(ll_to_earth(CAST(s.latitude as float), CAST(s.longitude as float)), ll_to_earth(:latitude, :longitude)) < :radisus", nativeQuery = true)
시/군과 몇 Km 내의 가맹점 데이터를 가져오는지 findBySigoonAndEarthDistance
로 나타내었다.
사용자 요청으로부터 시군, 거리, 위도, 경도 파라미터를 전달받고,
postgres의 store 테이블의 값들을 이용해 함께 작성한다.
이제 API 엔드포인트를 위해 storeController.java
를 작성해본다.
GET /api/v1/store/near?page=0&sigoon=성남시&lat=37.394968&lng=127.111064
요청을 하게 되면 아래와 같은 응답을 받을 수 있게 된다
{
"data": {
"content": [
{
"id": 232346,
"title": "**약국",
"category": null,
"sigoon": "성남시",
"address": "경기도 성남시 분당구 판교역로 **",
"phoneNumber": "031-***-****",
"postCode": "13493",
"latitude": 37.401222,
"longitude": 127.110374,
"updateDate": "2019-06-30",
"bigCategory": null
},
{
"id": 230420,
"title": "(주)***",
"category": null,
"sigoon": "성남시",
"address": "경기도 성남시 분당구 이매로 **",
"phoneNumber": "031-***-****",
"postCode": "13564",
"latitude": 37.394947,
"longitude": 127.12235,
"updateDate": "2019-06-30",
"bigCategory": null
},
....
}
이것으로 Spring Data JPA Native Query와 Postgres 추가모듈인 earthdistance 를 이용해서 가까운 가맹점 조회 API를 구현을 마쳤다.
'Back-end' 카테고리의 다른 글
Go gRPC 서버에 REST API 요청 주고 받기 [grpc-gateway] (0) | 2020.12.31 |
---|---|
JPA User 테이블, Postgres reserved keyword 해결하기 (0) | 2020.08.12 |
WSL환경에서 Docker-compose 사용하기 (0) | 2020.04.26 |
alembic을 이용해 DB 마이그레이션 하기 (2) (2) | 2020.03.18 |
alembic을 이용해 DB 마이그레이션 하기 (1) (0) | 2020.03.16 |
댓글