diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java index 1bc335d..ecefb2b 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java @@ -360,7 +360,7 @@ public class GisServiceV2 { } } - // 3-a. hourly 범위 → L2 캐시 → DB fallback + // 3-a. hourly 범위 → L2 캐시 → DB fallback (누락 MMSI 부분 fallback 포함) if (split.hasHourlyRange()) { DailyTrackCacheManager.DateRange hr = split.getHourlyRange(); Map> hourlyTracks = @@ -373,6 +373,19 @@ public class GisServiceV2 { int totalPts = converted.stream().mapToInt(CompactVesselTrack::getPointCount).sum(); log.info("[CACHE-MONITOR] queryWithCache L2 HIT [{}, {}): cacheVessels={}, filteredVessels={}, compactTracks={}, points={}", hr.getStart(), hr.getEnd(), hourlyTracks.size(), filtered.size(), converted.size(), totalPts); + + // 캐시에 없는 MMSI → DB fallback + Set missingMmsis = new HashSet<>(requestedMmsis); + missingMmsis.removeAll(filtered.keySet()); + if (!missingMmsis.isEmpty()) { + VesselTracksRequest fallbackReq = VesselTracksRequest.builder() + .startTime(hr.getStart()).endTime(hr.getEnd()) + .vessels(new ArrayList<>(missingMmsis)).build(); + List dbResult = gisService.getVesselTracks(fallbackReq); + allTracks.addAll(dbResult); + log.info("[CACHE-MONITOR] queryWithCache L2 PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}", + filtered.size(), missingMmsis.size(), dbResult.size()); + } } else { VesselTracksRequest hourlyReq = VesselTracksRequest.builder() .startTime(hr.getStart()).endTime(hr.getEnd()) @@ -384,7 +397,7 @@ public class GisServiceV2 { } } - // 3-b. 5min 범위 → L1 캐시 → DB fallback + // 3-b. 5min 범위 → L1 캐시 → DB fallback (누락 MMSI 부분 fallback 포함) if (split.hasFiveMinRange()) { DailyTrackCacheManager.DateRange fr = split.getFiveMinRange(); Map> fiveMinTracks = @@ -397,6 +410,19 @@ public class GisServiceV2 { int totalPts = converted.stream().mapToInt(CompactVesselTrack::getPointCount).sum(); log.info("[CACHE-MONITOR] queryWithCache L1 HIT [{}, {}): cacheVessels={}, filteredVessels={}, compactTracks={}, points={}", fr.getStart(), fr.getEnd(), fiveMinTracks.size(), filtered.size(), converted.size(), totalPts); + + // 캐시에 없는 MMSI → DB fallback + Set missingMmsis = new HashSet<>(requestedMmsis); + missingMmsis.removeAll(filtered.keySet()); + if (!missingMmsis.isEmpty()) { + VesselTracksRequest fallbackReq = VesselTracksRequest.builder() + .startTime(fr.getStart()).endTime(fr.getEnd()) + .vessels(new ArrayList<>(missingMmsis)).build(); + List dbResult = gisService.getVesselTracks(fallbackReq); + allTracks.addAll(dbResult); + log.info("[CACHE-MONITOR] queryWithCache L1 PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}", + filtered.size(), missingMmsis.size(), dbResult.size()); + } } else { VesselTracksRequest fiveMinReq = VesselTracksRequest.builder() .startTime(fr.getStart()).endTime(fr.getEnd())