최초검색 : 13724 ms
조회로직 변경 : 7847ms
Fetch Join 변경 : 319ms
조회 쿼리 변경 : 256ms
기본적인 주차장 검색기능을 구현했다.
{
"address_name":"제주특별자치도 서귀포시 성산읍 고성리 238",
"category_group_code":"PK6",
"category_group_name":"주차장",
"category_name":"교통,수송 \u003e 교통시설 \u003e 주차장",
"distance":"",
"id":"1648733158",
"phone":"",
"place_name":"스타벅스 제주성산DT점 주차장",
"place_url":"http://place.map.kakao.com/1648733158",
"road_address_name":"",
"x":"126.920615213766",
"y":"33.4497082943452"
}
검색어 유사도를 도입해 유사도가 가장 높은 항목의 좌표를 반환
키워드 검색 시 기존에 카카오 API만 검색하던 부분을 DB의 주차장 명칭도 포함
해결
코드에 키워드 유사도 로직 추가
if (parkSearchRequestDto.getKeyword() != null) {
//카카오 검색 API호출
KakaoSearchDto kakaoSearchDto = kakaoMapService.getKakaoSearch(parkSearchRequestDto.getKeyword());
if (kakaoSearchDto.getMeta().getTotal_count() > 0) {
List<KakaoSearchDocumentsDto> kakaoSearchDocumentsDto = kakaoSearchDto.getDocuments();
lo = kakaoSearchDocumentsDto.get(0).getX();
la = kakaoSearchDocumentsDto.get(0).getY();
placeName = kakaoSearchDocumentsDto.get(0).getPlace_name();
// 0번 결과로 유사도 초기화
similarScore = similarKeyword(parkSearchRequestDto.getKeyword(), kakaoSearchDocumentsDto.get(0).getPlace_name());
for (KakaoSearchDocumentsDto kakao : kakaoSearchDocumentsDto) {
// 검색결과 별 유사도 비교
searchSimilarScore = similarKeyword(parkSearchRequestDto.getKeyword(), kakao.getPlace_name());
if (searchSimilarScore < similarScore) {
lo = kakao.getX();
la = kakao.getY();
placeName = kakao.getPlace_name();
similarScore = searchSimilarScore;
}
}
}
// DB에서 Like검색
List<ParkInfo> parkInfos = parkInfoRepository.findByNameContains(parkSearchRequestDto.getKeyword());
for (ParkInfo parkInfo : parkInfos) {
// 검색결과 별 유사도 비교
searchSimilarScore = similarKeyword(parkSearchRequestDto.getKeyword(), parkInfo.getName());
if (searchSimilarScore < similarScore) {
la = parkInfo.getLa();
lo = parkInfo.getLo();
placeName = parkInfo.getName();
similarScore = searchSimilarScore;
}
}
//결과가 없을경우 리턴
if (placeName == null) {
return parkSearchResponseDto;
}
public static int similarKeyword(String userKeyword, String keyword) {
return LevenshteinDistance.getDefaultInstance().apply(userKeyword, keyword);
}
스타벅스 서귀포 검색 시 결과
스타벅스 서귀포DT 주차장 검색 결과
사용자 화면에서도 정상적으로 확인이 된다
result = parkInfoRepository.findParkInfoWithOperInfoAndTypeQueryDsl(lo, la, 2, ParkType.fromValue(parkSearchRequestDto.getType()));
for (ParkOperInfo park : result) {
String available;
// 현재 운영여부 확인
if (OperationChecking.checkOperation(LocalDateTime.now(), park)) {
// 현재 주차 가능 대수 = 주차 가능 대수 - 출차시간이 없는 현황 수(주차중인 경우)
available = (park.getCmprtCo() - parkMgtInfoRepository.countByParkInfoIdAndExitTimeIsNull(park.getParkInfo().getId())) + "대";
} else {
// 운영중이 아니라면 메시지 출력
available = MsgType.NOT_OPEN_NOW.getMsg();
}
ParkOperInfoDto parkOperInfoDto = ParkOperInfoDto.of(park, ParkingFeeCalculator.calculateParkingFee(parkSearchRequestDto.getParktime() * 60L, park), available);
if (parkOperInfoDto.getTotCharge() <= parkSearchRequestDto.getCharge()) {
parkOperInfoDtos.add(parkOperInfoDto);
}
}
@Override
public List<ParkOperInfo> findParkInfoWithOperInfoAndTypeQueryDsl(String x, String y, double distance, String type) {
Double longitude = Double.parseDouble(x);
Double latitude = Double.parseDouble(y);
BooleanBuilder builder = new BooleanBuilder();
builder.and(Expressions.booleanTemplate("ST_Distance_Sphere(Point({0}, {1}), Point({2}, {3})) < {4}", longitude, latitude, qParkInfo.lo, qParkInfo.la, 2000));
if (!type.equals("전체")) {
builder.and(qParkOperInfo.parkCtgy.eq(type));
}
return jpaQueryFactory.selectFrom(qParkOperInfo)
.join(qParkOperInfo.parkInfo, qParkInfo)
.where(builder)
.orderBy(Expressions.stringTemplate("ST_Distance_Sphere(Point({0}, {1}), Point({2}, {3}))", longitude, latitude, qParkInfo.lo, qParkInfo.la).asc())
.fetch();
}
추가 작업
기존 쿼리는 ST_Distance_Sphere를 이용하여 거리를 계산했는데 176ms가 소요되었다
거리 계산 공식을 적용하여 측정했을때는 84ms로 50%정도 더 빠른 효율을 보여 QueryDSL에 해당 쿼리를 적용시켰다