주변 정보 추천 기능 수정 1
마지막으로 현재 게시글의 주변에 있는 볼거리를 추천해주는 기능을 수정해줄 차례이다.
이전에 작성했던 방법은 완전 무식하게 모든 게시글을 불러와서 거리를 각각 비교해 준 후 일정 거리 안에 있는 게시글을 모아서 응답해주는 방법을 사용했다.
이것을 mysql의 point 자료형을 이용하는 방식으로 수정해보자.
mysql에서 지원하는 ST_distance_sphere 함수를 이용하면 두 좌표간의 거리를 구할 수 있다.
ST_distance_sphere (좌표1, 좌표2); => 두 좌표간의 거리가 m단위로 주어진다.
따라서 특정 위치에서 일정 거리내에 있는 테이블을 모두 조회하려면
// point 는 기준 위치정보
// board는 게시글 테이블 명 , geography는 위치정보 컬럼명
SET @point = POINT(128.59072079647405, 35.86729311520323);
select * from board b where ST_Distance_Sphere(geography, @point) <= 500;
이와 같이 쿼리를 구성하면 될 것이라고 생각했다.
역이요에서는 querydsl을 사용하지 않고 nativequery를 사용했었으므로 직접 작성을 했다.
@Query(value = "select * from board b where ST_Distance_Sphere(b.geography, :point) <= 500", nativeQuery = true)
List<Board> findAround(@Param("point")Point point);
mysql에서 작성했던 쿼리가 spring에선 동작하지 않았다 에러로그는 다음과 같다.
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 3037, SQLState: 22001
o.h.engine.jdbc.spi.SqlExceptionHelper : Data truncation: Invalid GIS data provided to function st_distance_sphere.
잘못된 형식의 데이터가 함수에 사용됐다는 것 같다.
챗GPT에 물어봤더니 String 형식을 파라미터로 넣는 것 같다.
@Query(value = "select * from board b where ST_Distance_Sphere(b.geography, :point) <= 500", nativeQuery = true)
List<Board> findAround(@Param("point")String point);
그랬더니 이번엔 다음과 같은 에러가 발생했다.
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 3548, SQLState: SR001
o.h.engine.jdbc.spi.SqlExceptionHelper : There's no spatial reference system with SRID 1313427280.
다시 챗 GPT에게 물어보니
.....
어느장단에 맞추라는 거지
...
결국 repository에서는 그대로 Point자료형을 입력하고
@Query(value = "SELECT * from board where ST_Distance_Sphere(geography, :point) <= 500", nativeQuery = true)
List<Board> findAround(@Param("point")Point point);
service단에서 point를 db에서 가져온 그대로 사용한것이 아닌 2차가공을 해주니 성공하였다.
// 기존 방법
List<Board> around = boardRepository.findAround(board.getGeography());// 근처 보드 정보
// 수정 방법
Point point = new GeometryFactory().createPoint(new Coordinate(board.getGeography().getX(), board.getGeography().getY()));
List<Board> around = boardRepository.findAround(point);// 근처 보드 정보
도저히 차이점이 뭔지 모르겠어서
다시 원래대로 getGeography()를 통해 얻은 point를 그대로 넣었더니
이번엔 또 정상적으로 동작한다...
그렇다면 결론은 처음에 nativequery를 잘못 작성했던 것 같다.
가까운 길을 멀리 돌아왔다...
주변 정보 추천 기능 수정 2
주변 정보추천 기능에서 현재 작성된 방식은
mysql에서 모든 게시글을 가져와서 기준 좌표에서 500m이내에 있는 게시글을 조회한다.
이를 좀 더 효율적으로 바꾸기위해 방법을 찾아봤다.
공간 인덱스(Spatial index)를 사용하면 성능을 향상시킬 수 있었다.
방식은 처음에 게시글을 모든 게시글을 가져오는 것이 아닌
현재 좌표 중심으로 원을그려 해당 범위내에 있는 게시글만 조회하는 것이다.
@Query(value = "SELECT * from board where ST_Contains(ST_Buffer(:point, 0.005),geography)", nativeQuery = true)
List<Board> findAround(@Param("point")Point point);
ST_Buffer(point, 0.01) 메서드를 사용하면 point를 기준으로 반경 1키로미터 만큼의 원을 그린다.
그리고 ST_Contains() 메서드를 사용하여 해당 범위 내에 좌표가 있는 게시글을 찾는다.
모든 게시글을 조회하는 것에서 범위 내의 게시글을 조회하는 방식으로 바꾸는 것이기에
유의미한 성능 변화가 있는 것 같다.
프로젝트를 마무리한지 4달정도 지나고 리팩토링을 한 것인데 새로 공부하고 알게된 내용이 있어서 수정할 부분이 꽤 있었다. 리팩토링을 하면서 mysql의 Point자료형에 대해서 많이 공부해볼 수 있었고 nativequery 사용법도 복습해보며 좋은 공부가 됐다.
'공부 일지 > 개인 공부 기록용' 카테고리의 다른 글
[JPA] N+1 문제 (0) | 2023.05.22 |
---|---|
에러로그 (mysqladmin flush-hosts) (0) | 2023.05.19 |
프로젝트 역이요 - 리팩토링 2일차 (0) | 2023.05.13 |
프로젝트 역이요 - 리팩토링 1일차 (0) | 2023.05.11 |
23/05/08 (0) | 2023.05.09 |