[혼자왔니] postGIS를 활용한 인근 피드 조회

Update:     Updated:

카테고리:

태그:

공간 데이터를 다뤄야 하는 상황

사용자의 모집글에는 다음과 같은 내용이 포함된다.
image

따라서, 사용자가 게시글을 검색할 때 자신의 현재 위치 근방 1.5km 내에 있는 음식점들에 대한 모집글만 조회할 수 있도록 기능을 만들기 위해 자신의 위치 인근 게시글을 탐색해야 하는 상황이 생긴다.

postgreSQL의 postGIS 익스텐션을 활용해보자.

공간 데이터를 다룰 때 사용성과 성능 측면에서 월등하다고 알려진 postgreSQLpostGIS를 사용해보기로 했다.

라이브러리 및 설정 파일 세팅

// hibernate-spatial
implementation 'org.hibernate:hibernate-spatial:5.6.11.Final'

// postgresql
runtimeOnly 'org.postgresql:postgresql:42.5.4'
spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: # url
    username: # username
    password: # password

  jpa:
    database: postgresql
    database-platform: org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect

Point 객체를 이용해서 위치에 대한 정보를 저장하자.

사용자의 좌표, 음식점의 좌표 이 두 가지 값을 가지고 둘 사이의 거리를 측정하여 일정 거리 미만에 해당하는 값들만 불러올 예정이다. 따라서 위도, 경도로 초기화시킨 point 객체가 필요하다.

@Table(name = "post")
@Entity
public class Post extends BaseEntity {
    ...
    @Column(columnDefinition = "geometry(Point, 4326)", nullable = false)
    private Point restaurantPoint;  // 음식점(Point) 객체
    ...
}
import org.locationtech.jts.geom.*;

// 0(좌표 평면), 4326(위도-경도 좌표계)
private GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);  

/**
 * 위도, 경도를 받아 Point 객체를 반환하는 메소드
 *
 * @param latitude
 * @param longitude
 * @return
 */
private Point getPoint(double latitude, double longitude) {
    Point point = geometryFactory.createPoint(new Coordinate(latitude, longitude));

    return point;
}

SRID는 좌표계를 나타내는 값으로, 자주 사용하는 값은 0(좌표평면)과 4326(위도-경도 좌표계)이다.
PostGIS와 MySQL의 가장 큰 차이점은 바로 4326 좌표계에서도 다양한 함수를 사용할 수 있다는 것이다.
(MySQL은 4326으로 지정해도 결국 좌표평면 좌표계 기준으로 공간 데이터를 다룬다)

인근 게시글을 조회하기 위한 쿼리를 작성해보자.

postGIS에는 거리를 측정하는 다양한 함수가 있다.
그 중 ST_DWithin 함수를 사용하고자 한다.
해당 함수를 JPQL 형식으로 PostRepository에 적용시켜주었다.

public interface PostRepository extends JpaRepository<Post, Long> {
    @Query(value = "select p from Post p where dwithin(p.restaurantPoint, :point, 1500, false) is true and p.isActive is true")
    Page<Post> findPostByDistance(Pageable pageable, Point point);
}

더 살펴볼 내용들

image

아무래도 인근 좌표를 찾기 위해 왠지 post table을 full scan할 것 같다는 것이 조금 우려스럽다.
따라서,

  1. point 객체가 적용되어있는 restaurant_point column에 인덱스를 건다든지,
  2. ST_DWithin 함수 외에 postGIS에서 제공하는 거리 측정 관련 여러 함수들의 query plan을 비교하여 더 적합한 함수를 찾는 등

추후에 성능적인 이슈를 생각해보려고 한다.

Reference

1) https://gksdudrb922.tistory.com/245 [postGIS 초기 세팅]

RUAlone 카테고리 내 다른 글 보러가기

댓글 남기기