늦은 프로그래밍 이야기

230216 TIL (최종프로젝트) 본문

내일배움캠프/TIL, WIL

230216 TIL (최종프로젝트)

한정규 2023. 2. 17. 00:21

프로젝트

검색 키워드로 레스토랑 목록 조회

키워드로 검색하면 해당 키워드를 가지고 있는 레스토랑만 조회해서 보여주는 기능을 구현하였다. 처음에는 그냥 키워드를 받아서 해당 키워드에 해당하는 레스토랑을 반환하는 쉬운 기능인줄 알았는데, 반환 값에 현재 유저의 위치와 레스토랑의 위치 간의 거리를 구해서 반환해야 하는 기능이었다.

검색 기능에 LIKE 이외의 다른 쿼리문을 사용할 수 있는지

검색 기능에 LIKE 문을 사용하여 레스토랑이 가지고 있는 키워드 값이 “XX XXX XX”의 형태여서 와일드카드를 사용하여 입력받은 키워드 값을 포함하고 있는 레스토랑을 가져오는 JPA 쿼리메소드를 구현하였는데 그동안 LIKE 문과 와일드카드를 함께 사용하면 성능도 안나오고 실무에서 거의 사용하지 않는다고 많이 들어와서 위처럼 사용하기 싫었다.

그래서 다른 방법을 구글링하며 장시간 찾아보았지만, 결국 모든 블로그에서는 LIKE와 와일드카드를 사용해서 검색하는 방법 밖에 나오지 않았고, 요즘 핫하다는 ChatGPT에게 물어보았다.

그렇다고 한다.. ChatGPT는 실무를 해보지 않아서 방법을 모르는 듯 했다. 일단은 여기서 시간을 지체할 수 없어서 추후 리팩토링하며 튜터님들에게 질문해서 방법을 모색해봐야 할 것이다.

혹시 몰라 다시 raw query나 QueryDSL까지 확장하여 질문해 보았는데 다음과 같은 답변이 돌아왔다.

QueryDSL의 방법은 아직 QueryDSL을 공부하지 않아서 QueryDSL을 공부한 후에 해당 메소드 내부를 살펴보며 와일드카드보다 효율이 좋을지 고민해 보아야 할 것이고, Native Query의 방법은 내가 작성한 JPQL과 비교하여 정말로 와일드카드가 사용되지 않고 조회가 되는지 확인을 해보고 적용해야 할 것이다. 일단 JPQL로 작성한 코드가 저것과 같이 간단하지는 않아서 바로 적용을 해볼 수는 없을 것 같고 일단은 MVP를 빠르게 완성하고 리팩토링 할 때 적용을 해보아야겠다.

@Query(value = "select new team.waitingcatch.app.restaurant.dto.restaurant.SearchRestaurantJpaResponse("
   + "r.name, r.images, i.rate, r.searchKeywords, r.position, i.currentWaitingNumber, i.isLineupActiveStatus) "
   + "from Restaurant r join fetch RestaurantInfo i on r.id = i.restaurant.id "
   + "where r.searchKeywords like %:keyword%")
List<SearchRestaurantJpaResponse> findRestaurantsBySearchKeywordsContaining(String keyword);

초반 회의 때 거리계산이 필요하고 지도상에서 경도와 위도 데이터를 받아올 것을 염두에 두어 SA문서에 저장해 둔 경도와 위도를 사용하여 거리를 계산하는 산식을 사용한 메소드로 위에서 받아온 값들 중에 position내에 경도와 위도가 있는데 그 데이터들을 이용하여 거리를 계산하여 반환해 주었다.

public double distanceInKilometerByHaversine(double x1, double y1, double x2, double y2) {
   double distance;
   double radius = 6371;// 지구 반지름(km)
   double toRadian = Math.PI/ 180;
   double deltaLatitude = Math.abs(x1 - x2) * toRadian;
   double deltaLongitude = Math.abs(y1 - y2) * toRadian;
   double sinDeltaLat = Math.sin(deltaLatitude / 2);
   double sinDeltaLng = Math.sin(deltaLongitude / 2);
   double squareRoot = Math.sqrt(
      sinDeltaLat * sinDeltaLat + Math.cos(x1 * toRadian) * Math.cos(x2 * toRadian) * sinDeltaLng * sinDeltaLng);
   distance = 2 * radius * Math.asin(squareRoot);
   return distance;
}

대충 위도와 경도를 좌표로 사용하여 유클리드 거리법(?) 비슷하게 계산하는 것 같은데 이과생이 아니어서 정확히 어떠한 방식으로 도출해 내는지는 아직 모르지만, 테스트 코드를 통해 정확한 값을 계산하여 반환해 주는 것을 확인 하였다.


Comments