diff --git a/src/main/java/com/wayble/server/direction/dto/InternalStep.java b/src/main/java/com/wayble/server/direction/dto/internal/InternalStep.java similarity index 92% rename from src/main/java/com/wayble/server/direction/dto/InternalStep.java rename to src/main/java/com/wayble/server/direction/dto/internal/InternalStep.java index a41c6631..d4ecdc81 100644 --- a/src/main/java/com/wayble/server/direction/dto/InternalStep.java +++ b/src/main/java/com/wayble/server/direction/dto/internal/InternalStep.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.dto; +package com.wayble.server.direction.dto.internal; import java.util.List; diff --git a/src/main/java/com/wayble/server/direction/dto/NodeRef.java b/src/main/java/com/wayble/server/direction/dto/internal/NodeRef.java similarity index 68% rename from src/main/java/com/wayble/server/direction/dto/NodeRef.java rename to src/main/java/com/wayble/server/direction/dto/internal/NodeRef.java index d6d7f543..c26e6d40 100644 --- a/src/main/java/com/wayble/server/direction/dto/NodeRef.java +++ b/src/main/java/com/wayble/server/direction/dto/internal/NodeRef.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.dto; +package com.wayble.server.direction.dto.internal; public record NodeRef( Long id, diff --git a/src/main/java/com/wayble/server/direction/dto/TransportationGraphDto.java b/src/main/java/com/wayble/server/direction/dto/internal/TransportationGraphDto.java similarity index 89% rename from src/main/java/com/wayble/server/direction/dto/TransportationGraphDto.java rename to src/main/java/com/wayble/server/direction/dto/internal/TransportationGraphDto.java index ebdddb47..b061b6fa 100644 --- a/src/main/java/com/wayble/server/direction/dto/TransportationGraphDto.java +++ b/src/main/java/com/wayble/server/direction/dto/internal/TransportationGraphDto.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.dto; +package com.wayble.server.direction.dto.internal; import com.wayble.server.direction.entity.transportation.Edge; import org.springframework.data.util.Pair; diff --git a/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java b/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java index 0977327c..af8c4c5c 100644 --- a/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java +++ b/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java @@ -8,10 +8,12 @@ @RequiredArgsConstructor public enum DirectionErrorCase implements ErrorCase { - PATH_NOT_FOUND(400, 4001, "해당하는 경로를 찾을 수 없습니다."), - ES_INDEXING_FAILED(500, 4002, "ElasticSearch 인덱싱에 실패했습니다."), - HISTORY_NOT_FOUND(400, 4004, "검색 기록이 없습니다."), - DISTANCE_TOO_FAR(400, 4002, "거리가 30km 이상입니다."); + ES_INDEXING_FAILED(500, 4001, "ElasticSearch 인덱싱에 실패했습니다."), + HISTORY_NOT_FOUND(400, 4002, "검색 기록이 없습니다."), + + PATH_NOT_FOUND(400, 4003, "해당하는 경로를 찾을 수 없습니다."), + DISTANCE_TOO_FAR(400, 4004, "거리가 30km 이상입니다."), + NO_NEARBY_STATIONS(400, 4005, "주변에 정류장이 없습니다."); private final Integer httpStatusCode; private final Integer errorCode; diff --git a/src/main/java/com/wayble/server/direction/repository/EdgeBoundingBoxProjection.java b/src/main/java/com/wayble/server/direction/repository/transportation/EdgeBoundingBoxProjection.java similarity index 87% rename from src/main/java/com/wayble/server/direction/repository/EdgeBoundingBoxProjection.java rename to src/main/java/com/wayble/server/direction/repository/transportation/EdgeBoundingBoxProjection.java index 66e911d1..16589705 100644 --- a/src/main/java/com/wayble/server/direction/repository/EdgeBoundingBoxProjection.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/EdgeBoundingBoxProjection.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.type.DirectionType; diff --git a/src/main/java/com/wayble/server/direction/repository/EdgeRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/EdgeRepository.java similarity index 92% rename from src/main/java/com/wayble/server/direction/repository/EdgeRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/EdgeRepository.java index d0dbce87..c6b3c365 100644 --- a/src/main/java/com/wayble/server/direction/repository/EdgeRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/EdgeRepository.java @@ -1,7 +1,8 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.transportation.Edge; -import com.wayble.server.direction.repository.EdgeBoundingBoxProjection; +import com.wayble.server.direction.repository.transportation.EdgeBoundingBoxProjection; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; diff --git a/src/main/java/com/wayble/server/direction/repository/ElevatorRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/ElevatorRepository.java similarity index 89% rename from src/main/java/com/wayble/server/direction/repository/ElevatorRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/ElevatorRepository.java index c659d629..1a5930a3 100644 --- a/src/main/java/com/wayble/server/direction/repository/ElevatorRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/ElevatorRepository.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.transportation.Elevator; import com.wayble.server.direction.entity.transportation.Facility; diff --git a/src/main/java/com/wayble/server/direction/repository/FacilityRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/FacilityRepository.java similarity index 87% rename from src/main/java/com/wayble/server/direction/repository/FacilityRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/FacilityRepository.java index 77b4ab09..514b862f 100644 --- a/src/main/java/com/wayble/server/direction/repository/FacilityRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/FacilityRepository.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.transportation.Facility; diff --git a/src/main/java/com/wayble/server/direction/repository/NodeBoundingBoxProjection.java b/src/main/java/com/wayble/server/direction/repository/transportation/NodeBoundingBoxProjection.java similarity index 79% rename from src/main/java/com/wayble/server/direction/repository/NodeBoundingBoxProjection.java rename to src/main/java/com/wayble/server/direction/repository/transportation/NodeBoundingBoxProjection.java index b5a02b97..69f3f651 100644 --- a/src/main/java/com/wayble/server/direction/repository/NodeBoundingBoxProjection.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/NodeBoundingBoxProjection.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.type.DirectionType; diff --git a/src/main/java/com/wayble/server/direction/repository/NodeRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/NodeRepository.java similarity index 86% rename from src/main/java/com/wayble/server/direction/repository/NodeRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/NodeRepository.java index b5b0bc52..00646aab 100644 --- a/src/main/java/com/wayble/server/direction/repository/NodeRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/NodeRepository.java @@ -1,7 +1,8 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.transportation.Node; -import com.wayble.server.direction.repository.NodeBoundingBoxProjection; +import com.wayble.server.direction.repository.transportation.NodeBoundingBoxProjection; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; diff --git a/src/main/java/com/wayble/server/direction/repository/RouteRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/RouteRepository.java similarity index 88% rename from src/main/java/com/wayble/server/direction/repository/RouteRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/RouteRepository.java index c052ecc5..3d6cee9d 100644 --- a/src/main/java/com/wayble/server/direction/repository/RouteRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/RouteRepository.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/src/main/java/com/wayble/server/direction/repository/WheelchairInfoRepository.java b/src/main/java/com/wayble/server/direction/repository/transportation/WheelchairInfoRepository.java similarity index 91% rename from src/main/java/com/wayble/server/direction/repository/WheelchairInfoRepository.java rename to src/main/java/com/wayble/server/direction/repository/transportation/WheelchairInfoRepository.java index 41aea5f4..5907b70e 100644 --- a/src/main/java/com/wayble/server/direction/repository/WheelchairInfoRepository.java +++ b/src/main/java/com/wayble/server/direction/repository/transportation/WheelchairInfoRepository.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.repository; +package com.wayble.server.direction.repository.transportation; import com.wayble.server.direction.entity.transportation.Wheelchair; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/wayble/server/direction/service/BusInfoService.java b/src/main/java/com/wayble/server/direction/service/BusInfoService.java index fec024bc..99fccdef 100644 --- a/src/main/java/com/wayble/server/direction/service/BusInfoService.java +++ b/src/main/java/com/wayble/server/direction/service/BusInfoService.java @@ -7,10 +7,9 @@ import com.wayble.server.direction.external.opendata.OpenDataProperties; import com.wayble.server.direction.external.opendata.dto.OpenDataResponse; import com.wayble.server.direction.external.opendata.dto.StationSearchResponse; -import com.wayble.server.direction.repository.RouteRepository; +import com.wayble.server.direction.repository.transportation.RouteRepository; import com.wayble.server.direction.dto.response.TransportationResponseDto; -import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -31,11 +30,6 @@ public TransportationResponseDto.BusInfo getBusInfo(String stationName, Long bus List isLowFloor = new ArrayList<>(); Integer dispatchInterval = null; - // 나중에 서비스키 문제 해결되면 이 함수 호출 제거 - return createDummyBusInfo(stationName, busId, x, y); - - - /* boolean isShuttleBus = false; if (busId != null) { var routeName = routeRepository.findRouteNameById(busId); @@ -103,29 +97,7 @@ public TransportationResponseDto.BusInfo getBusInfo(String stationName, Long bus } return new TransportationResponseDto.BusInfo(isShuttleBus, isLowFloor, dispatchInterval); - */ - - } - - // 나중에 이 함수 제거 - private TransportationResponseDto.BusInfo createDummyBusInfo(String stationName, Long busId, Double x, Double y) { - - // 셔틀버스 여부 확인 (기존 로직 유지) - boolean isShuttleBus = false; - if (busId != null) { - var route = routeRepository.findById(busId); - isShuttleBus = route.isPresent() && route.get().getRouteName().contains("마포"); - } - - // 랜덤 더미 데이터 생성 - List isLowFloor = new ArrayList<>(); - isLowFloor.add(Math.random() < 0.7); - isLowFloor.add(Math.random() < 0.5); - Integer dispatchInterval = (int) (Math.random() * 15) + 1; - - - return new TransportationResponseDto.BusInfo(isShuttleBus, isLowFloor, dispatchInterval); } private OpenDataResponse fetchArrivals(String stationId, Long busId) { diff --git a/src/main/java/com/wayble/server/direction/service/FacilityService.java b/src/main/java/com/wayble/server/direction/service/FacilityService.java index 77715b54..7ae2f6d6 100644 --- a/src/main/java/com/wayble/server/direction/service/FacilityService.java +++ b/src/main/java/com/wayble/server/direction/service/FacilityService.java @@ -8,12 +8,12 @@ import com.wayble.server.direction.external.kric.dto.KricToiletRawItem; import com.wayble.server.direction.external.kric.dto.KricToiletRawResponse; +import com.wayble.server.direction.repository.transportation.ElevatorRepository; +import com.wayble.server.direction.repository.transportation.FacilityRepository; +import com.wayble.server.direction.repository.transportation.NodeRepository; +import com.wayble.server.direction.repository.transportation.RouteRepository; +import com.wayble.server.direction.repository.transportation.WheelchairInfoRepository; -import com.wayble.server.direction.repository.ElevatorRepository; -import com.wayble.server.direction.repository.FacilityRepository; -import com.wayble.server.direction.repository.NodeRepository; -import com.wayble.server.direction.repository.RouteRepository; -import com.wayble.server.direction.repository.WheelchairInfoRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.Builder; diff --git a/src/main/java/com/wayble/server/direction/service/TransportationService.java b/src/main/java/com/wayble/server/direction/service/TransportationService.java index 6a37f975..7016253b 100644 --- a/src/main/java/com/wayble/server/direction/service/TransportationService.java +++ b/src/main/java/com/wayble/server/direction/service/TransportationService.java @@ -1,19 +1,21 @@ package com.wayble.server.direction.service; import com.wayble.server.common.exception.ApplicationException; -import com.wayble.server.direction.dto.InternalStep; -import com.wayble.server.direction.dto.NodeRef; -import com.wayble.server.direction.dto.TransportationGraphDto; +import com.wayble.server.direction.dto.internal.InternalStep; +import com.wayble.server.direction.dto.internal.NodeRef; +import com.wayble.server.direction.dto.internal.TransportationGraphDto; import com.wayble.server.direction.dto.request.TransportationRequestDto; import com.wayble.server.direction.dto.response.TransportationResponseDto; import com.wayble.server.direction.entity.transportation.Edge; import com.wayble.server.direction.entity.transportation.Node; import com.wayble.server.direction.entity.transportation.Route; import com.wayble.server.direction.entity.type.DirectionType; -import com.wayble.server.direction.repository.EdgeBoundingBoxProjection; -import com.wayble.server.direction.repository.EdgeRepository; -import com.wayble.server.direction.repository.NodeBoundingBoxProjection; -import com.wayble.server.direction.repository.NodeRepository; +import com.wayble.server.direction.repository.transportation.EdgeBoundingBoxProjection; +import com.wayble.server.direction.repository.transportation.EdgeRepository; +import com.wayble.server.direction.repository.transportation.NodeBoundingBoxProjection; +import com.wayble.server.direction.repository.transportation.NodeRepository; +import com.wayble.server.direction.service.util.HaversineUtil; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; @@ -24,6 +26,7 @@ import static com.wayble.server.direction.exception.DirectionErrorCase.PATH_NOT_FOUND; import static com.wayble.server.direction.exception.DirectionErrorCase.DISTANCE_TOO_FAR; +import static com.wayble.server.direction.exception.DirectionErrorCase.NO_NEARBY_STATIONS; @Slf4j @Service @RequiredArgsConstructor @@ -52,50 +55,78 @@ private NodeRef toNodeRef(Node node) { } public TransportationResponseDto findRoutes(TransportationRequestDto request){ - - TransportationRequestDto.Location origin = request.origin(); - TransportationRequestDto.Location destination = request.destination(); - // 1. 거리 검증 (30km 제한) - double distance = haversine(origin.latitude(), origin.longitude(), - destination.latitude(), destination.longitude()); - if (distance >= DISTANCE_CONSTRAINT) { - throw new ApplicationException(DISTANCE_TOO_FAR); - } + List> allRoutes = null; + List> pagedRoutes = null; + List routeList = null; + TransportationRequestDto.Location origin = null; + TransportationRequestDto.Location destination = null; + Node start = null; + Node end = null; + TransportationResponseDto.PageInfo pageInfo = null; + + try { + origin = request.origin(); + destination = request.destination(); + // 1. 거리 검증 (30km 제한) + double distance = HaversineUtil.haversineKm(origin.latitude(), origin.longitude(), + destination.latitude(), destination.longitude()); + if (distance >= DISTANCE_CONSTRAINT) { + throw new ApplicationException(DISTANCE_TOO_FAR); + } - // 2. 임시 노드 생성 - Node start = Node.createNode(-1L, origin.name(), DirectionType.FROM_WAYPOINT ,origin.latitude(), origin.longitude()); - Node end = Node.createNode(-2L, destination.name(), DirectionType.TO_WAYPOINT,destination.latitude(), destination.longitude()); + // 2. 임시 노드 생성 + start = Node.createNode(-1L, origin.name(), DirectionType.FROM_WAYPOINT ,origin.latitude(), origin.longitude()); + end = Node.createNode(-2L, destination.name(), DirectionType.TO_WAYPOINT,destination.latitude(), destination.longitude()); - // 3. 여러 경로 찾기 - List> allRoutes = findMultipleTransportationRoutes(start, end); + // 3. 여러 경로 찾기 + allRoutes = findMultipleTransportationRoutes(start, end); - // 4. 페이징 처리 - int startIndex = (request.cursor() != null) ? request.cursor() : 0; - int pageSize = (request.size() != null) ? request.size() : 5; // 기본값 5로 설정 - int endIndex = Math.min(startIndex + pageSize, allRoutes.size()); - boolean hasNext = endIndex < allRoutes.size(); - Integer nextCursor = hasNext ? endIndex : null; - TransportationResponseDto.PageInfo pageInfo = new TransportationResponseDto.PageInfo(nextCursor, hasNext); + // 4. 페이징 처리 + int startIndex = (request.cursor() != null) ? request.cursor() : 0; + int pageSize = (request.size() != null) ? request.size() : 5; // 기본값 5로 설정 + int endIndex = Math.min(startIndex + pageSize, allRoutes.size()); + boolean hasNext = endIndex < allRoutes.size(); + Integer nextCursor = hasNext ? endIndex : null; + pageInfo = new TransportationResponseDto.PageInfo(nextCursor, hasNext); - // 경로를 찾지 못한 경우 처리 - if (allRoutes.isEmpty()) { - throw new ApplicationException(PATH_NOT_FOUND); - } + // 경로를 찾지 못한 경우 처리 + if (allRoutes.isEmpty()) { + throw new ApplicationException(PATH_NOT_FOUND); + } - // 페이징된 경로들을 Route 객체로 변환 - List routeList = new ArrayList<>(); - List> pagedRoutes = allRoutes.subList(startIndex, endIndex); - for (int i = 0; i < pagedRoutes.size(); i++) { - List internalRoute = pagedRoutes.get(i); + // 페이징된 경로들을 Route 객체로 변환 + routeList = new ArrayList<>(); + pagedRoutes = allRoutes.subList(startIndex, endIndex); + + for (int i = 0; i < pagedRoutes.size(); i++) { + List internalRoute = pagedRoutes.get(i); + + List enrichedRoute = enrichRoutesWithServiceInfo(internalRoute); + + TransportationResponseDto.Route routeObj = createRoute(enrichedRoute, startIndex + i + 1); + routeList.add(routeObj); + } - // InternalStep을 TransportationResponseDto.Step으로 변환 (API 호출 포함) - List enrichedRoute = enrichRoutesWithServiceInfo(internalRoute); + TransportationResponseDto result = new TransportationResponseDto(routeList, pageInfo); - TransportationResponseDto.Route routeObj = createRoute(enrichedRoute, startIndex + i + 1); - routeList.add(routeObj); + return result; + } finally { + // 메모리 정리 + if (allRoutes != null) { + allRoutes.clear(); + allRoutes = null; + } + if (pagedRoutes != null) { + pagedRoutes = null; + } + routeList = null; + + origin = null; + destination = null; + start = null; + end = null; + pageInfo = null; } - - return new TransportationResponseDto(routeList, pageInfo); } private TransportationResponseDto.Route createRoute(List steps, int routeIndex) { @@ -178,7 +209,7 @@ private List> findMultipleTransportationRoutes(Node startTmp, Node nearestToEnd = findNearestNode(nodes, endTmp.getLatitude(), endTmp.getLongitude()); if (nearestToStart == null || nearestToEnd == null) { - throw new ApplicationException(PATH_NOT_FOUND); + throw new ApplicationException(NO_NEARBY_STATIONS); } // 3. 임시 노드 추가 @@ -193,9 +224,9 @@ private List> findMultipleTransportationRoutes(Node startTmp, return result; - } catch (OutOfMemoryError e) { - log.error("Out of memory error in transportation route finding: {}", e.getMessage()); - throw new ApplicationException(PATH_NOT_FOUND); + } catch (Exception e) { + log.error("Unexpected error in transportation route finding: {}", e.getMessage(), e); + throw e; } finally { // 5. 메모리 정리 (finally 블록에서 확실히 실행) if (nodes != null) { @@ -316,6 +347,16 @@ private List> findAlternativeRoutesEfficiently( usedEdges.addAll(newUsedEdges); alternativeRoutes.add(newRoute); + + // 메모리 정리 + if (newUsedEdges != null) { + newUsedEdges.clear(); + newUsedEdges = null; + } + if (penalizedWeightMap != null) { + penalizedWeightMap.clear(); + penalizedWeightMap = null; + } } return alternativeRoutes; @@ -456,7 +497,7 @@ private TransportationGraphDto buildGraph(List nodes, List edges, No graph.get(startId).add(edge); - int weight = (int)(haversine( + int weight = (int)(HaversineUtil.haversineKm( start.getLatitude(), start.getLongitude(), end.getLatitude(), end.getLongitude() ) * METER_CONVERSION); @@ -481,11 +522,14 @@ private void addOriginDestinationWalkConnections(Map> graph, Ma // 2. 출발지에서 인근 정류장으로 도보 연결 List startCandidates = findNearbyNodes(nodes, startTmp.getLatitude(), startTmp.getLongitude(), ORIGIN_DESTINATION_WALK_DISTANCE); + if (startCandidates.isEmpty()) { + throw new ApplicationException(NO_NEARBY_STATIONS); + } for (Node candidate : startCandidates) { Edge walkEdge = Edge.createEdge(-1L, startNode, candidate, DirectionType.WALK); graph.get(startNode.getId()).add(walkEdge); - int weight = (int)(haversine( + int weight = (int)(HaversineUtil.haversineKm( startNode.getLatitude(), startNode.getLongitude(), candidate.getLatitude(), candidate.getLongitude() ) * METER_CONVERSION); @@ -494,6 +538,9 @@ private void addOriginDestinationWalkConnections(Map> graph, Ma // 3. 인근 정류장에서 도착지로 도보 연결 List endCandidates = findNearbyNodes(nodes, endTmp.getLatitude(), endTmp.getLongitude(), ORIGIN_DESTINATION_WALK_DISTANCE); + if (endCandidates.isEmpty()) { + throw new ApplicationException(NO_NEARBY_STATIONS); + } for (Node candidate : endCandidates) { Edge walkEdge = Edge.createEdge(-2L, candidate, endNode, DirectionType.WALK); @@ -502,7 +549,7 @@ private void addOriginDestinationWalkConnections(Map> graph, Ma } graph.get(candidate.getId()).add(walkEdge); - int weight = (int)(haversine( + int weight = (int)(HaversineUtil.haversineKm( candidate.getLatitude(), candidate.getLongitude(), endNode.getLatitude(), endNode.getLongitude() ) * METER_CONVERSION); @@ -529,11 +576,11 @@ private List findNearbyNodes(List nodes, double lat, double lon, int } // 정확한 거리 계산 - double distance = haversine(lat, lon, node.getLatitude(), node.getLongitude()) * METER_CONVERSION; + double distance = HaversineUtil.haversineKm(lat, lon, node.getLatitude(), node.getLongitude()) * METER_CONVERSION; return distance <= maxDistanceMeters; }) .sorted(Comparator.comparingDouble(node -> - haversine(lat, lon, node.getLatitude(), node.getLongitude()))) + HaversineUtil.haversineKm(lat, lon, node.getLatitude(), node.getLongitude()))) .limit(MAX_NEARBY_NODES) .collect(Collectors.toList()); } @@ -559,8 +606,10 @@ private List runDijkstra(Map> graph, Node start, } distance.put(start.getId(), 0); + // PriorityQueue 크기 제한 + final Map finalDistance = distance; PriorityQueue pq = new PriorityQueue<>(Math.min(1000, nodes.size()), - Comparator.comparingInt(n -> distance.get(n.getId()))); + Comparator.comparingInt(n -> finalDistance.getOrDefault(n.getId(), Integer.MAX_VALUE))); pq.add(start); int visitedCount = 0; @@ -593,7 +642,7 @@ private List runDijkstra(Map> graph, Node start, for (Node nearbyNode : nearbyNodes) { if (visited.contains(nearbyNode.getId())) continue; - double walkDistance = haversine( + double walkDistance = HaversineUtil.haversineKm( curr.getLatitude(), curr.getLongitude(), nearbyNode.getLatitude(), nearbyNode.getLongitude() ) * METER_CONVERSION; @@ -628,7 +677,7 @@ private List runDijkstra(Map> graph, Node start, Pair key = Pair.of(edge.getStartNode().getId(), edge.getEndNode().getId()); int baseWeight = weightMap.getOrDefault(key, - (int)(haversine( + (int)(HaversineUtil.haversineKm( edge.getStartNode().getLatitude(), edge.getStartNode().getLongitude(), edge.getEndNode().getLatitude(), edge.getEndNode().getLongitude() ) * METER_CONVERSION) @@ -690,7 +739,9 @@ private List runDijkstra(Map> graph, Node start, current = prevNode.get(current.getId()); } - return mergeConsecutiveRoutes(pathEdges, requestId); + List result = mergeConsecutiveRoutes(pathEdges, requestId); + + return result; } private List enrichRoutesWithServiceInfo(List steps) { @@ -801,7 +852,7 @@ private List mergeConsecutiveRoutes(List pathEdges, long req Node walkEndNode = pathEdges.get(j - 1).getEndNode(); if (walkStartNode != null && walkEndNode != null) { - double distanceKm = haversine( + double distanceKm = HaversineUtil.haversineKm( walkStartNode.getLatitude(), walkStartNode.getLongitude(), walkEndNode.getLatitude(), walkEndNode.getLongitude() ); @@ -922,7 +973,7 @@ private int calculateTransferWalkDistance(String fromStation, String toStation, } if (fromNode != null && toNode != null) { - double distanceKm = haversine( + double distanceKm = HaversineUtil.haversineKm( fromNode.getLatitude(), fromNode.getLongitude(), toNode.getLatitude(), toNode.getLongitude() ); @@ -957,28 +1008,16 @@ private String getRouteName(List pathEdges, int start, int end) { return null; } - public static double haversine( - double lat1, double lon1, - double lat2, double lon2 - ) { - final int R = 6_371; // 지구 반지름 (km) - double φ1 = Math.toRadians(lat1); - double φ2 = Math.toRadians(lat2); - double Δφ = Math.toRadians(lat2 - lat1); - double Δλ = Math.toRadians(lon2 - lon1); - - double a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) - + Math.cos(φ1) * Math.cos(φ2) - * Math.sin(Δλ / 2) * Math.sin(Δλ / 2); - - double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - return R * c; // km 단위 거리 반환 - } + private Node findNearestNode(List nodes, double lat, double lon) { return nodes.stream() + .filter(node -> { + double distance = HaversineUtil.haversineKm(lat, lon, node.getLatitude(), node.getLongitude()) * 1000; // m 단위 + return distance <= ORIGIN_DESTINATION_WALK_DISTANCE; // 1000m 이내 + }) .min(Comparator.comparingDouble(n -> - haversine(lat, lon, n.getLatitude(), n.getLongitude()))) + HaversineUtil.haversineKm(lat, lon, n.getLatitude(), n.getLongitude()))) .orElse(null); } diff --git a/src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java b/src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java index 3baf2280..c3e6561d 100644 --- a/src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java +++ b/src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java @@ -13,4 +13,8 @@ public static double haversine(double lat1, double lon1, double lat2, double lon double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return EARTH_RADIUS * c; } + + public static double haversineKm(double lat1, double lon1, double lat2, double lon2) { + return haversine(lat1, lon1, lat2, lon2) / 1000.0; + } }