diff --git a/frontend/src/i18n/en.ts b/frontend/src/i18n/en.ts
index c33c0f0..bcd9e5b 100644
--- a/frontend/src/i18n/en.ts
+++ b/frontend/src/i18n/en.ts
@@ -83,7 +83,7 @@ const en = {
'pipeline.aisLatest': 'AIS Latest',
'pipeline.processLatest': 'Process Latest',
'pipeline.cacheOverview': 'Cache Overview',
- 'pipeline.cachedDays': 'days cached',
+ 'pipeline.cachedDays': ' days cached',
'pipeline.totalHitRate': 'Total Hit Rate',
'pipeline.dailyThroughput': 'Daily Throughput Trend',
'pipeline.totalProcessed': 'Total Processed',
diff --git a/frontend/src/pages/DataPipeline.tsx b/frontend/src/pages/DataPipeline.tsx
index a0b02ee..dbc57da 100644
--- a/frontend/src/pages/DataPipeline.tsx
+++ b/frontend/src/pages/DataPipeline.tsx
@@ -157,8 +157,8 @@ export default function DataPipeline() {
L3 (Daily)
-
{cacheDetails.l3_daily?.cachedDays ?? 0}
-
{t('pipeline.cachedDays')}
+
{formatNumber(cacheDetails.l3_daily?.totalVessels)}
+
{cacheDetails.l3_daily?.cachedDays ?? 0}{t('pipeline.cachedDays')}
{cache && (
diff --git a/src/main/java/gc/mda/signal_batch/batch/processor/DailyTrackMergeProcessor.java b/src/main/java/gc/mda/signal_batch/batch/processor/DailyTrackMergeProcessor.java
index 44041b1..4b7d770 100644
--- a/src/main/java/gc/mda/signal_batch/batch/processor/DailyTrackMergeProcessor.java
+++ b/src/main/java/gc/mda/signal_batch/batch/processor/DailyTrackMergeProcessor.java
@@ -35,7 +35,7 @@ import java.util.regex.Pattern;
public class DailyTrackMergeProcessor
implements ItemProcessor, AbnormalDetectionResult>, StepExecutionListener {
- private static final Pattern WKT_COORDS_PATTERN = Pattern.compile("LINESTRING M\\((.+)\\)");
+ private static final Pattern WKT_COORDS_PATTERN = Pattern.compile("LINESTRING M\\s*\\((.+)\\)");
private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final AbnormalTrackDetector abnormalTrackDetector;
@@ -217,7 +217,9 @@ public class DailyTrackMergeProcessor
private int countWktPoints(String wkt) {
if (wkt == null || !wkt.startsWith("LINESTRING M")) return 0;
try {
- String coords = wkt.substring("LINESTRING M(".length(), wkt.length() - 1);
+ int parenIdx = wkt.indexOf('(');
+ if (parenIdx < 0) return 0;
+ String coords = wkt.substring(parenIdx + 1, wkt.length() - 1);
return coords.split(",").length;
} catch (Exception e) {
return 0;
diff --git a/src/main/java/gc/mda/signal_batch/batch/processor/HourlyTrackMergeProcessor.java b/src/main/java/gc/mda/signal_batch/batch/processor/HourlyTrackMergeProcessor.java
index 12d397a..2d0c2ad 100644
--- a/src/main/java/gc/mda/signal_batch/batch/processor/HourlyTrackMergeProcessor.java
+++ b/src/main/java/gc/mda/signal_batch/batch/processor/HourlyTrackMergeProcessor.java
@@ -35,7 +35,7 @@ import java.util.regex.Pattern;
public class HourlyTrackMergeProcessor
implements ItemProcessor, AbnormalDetectionResult>, StepExecutionListener {
- private static final Pattern WKT_COORDS_PATTERN = Pattern.compile("LINESTRING M\\((.+)\\)");
+ private static final Pattern WKT_COORDS_PATTERN = Pattern.compile("LINESTRING M\\s*\\((.+)\\)");
private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final AbnormalTrackDetector abnormalTrackDetector;
@@ -212,7 +212,9 @@ public class HourlyTrackMergeProcessor
private int countWktPoints(String wkt) {
if (wkt == null || !wkt.startsWith("LINESTRING M")) return 0;
try {
- String coords = wkt.substring("LINESTRING M(".length(), wkt.length() - 1);
+ int parenIdx = wkt.indexOf('(');
+ if (parenIdx < 0) return 0;
+ String coords = wkt.substring(parenIdx + 1, wkt.length() - 1);
return coords.split(",").length;
} catch (Exception e) {
return 0;
diff --git a/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedDailyTrackReader.java b/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedDailyTrackReader.java
index fcbe38b..093e1ca 100644
--- a/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedDailyTrackReader.java
+++ b/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedDailyTrackReader.java
@@ -146,10 +146,15 @@ public class CacheBasedDailyTrackReader implements ItemReader>
|| (endPos == null && rs.getString("end_position") != null)) {
parseFailCount[0]++;
}
+ // ST_AsText()는 "LINESTRING M (...)" 공백 포함 반환 → Java 내부 형식으로 정규화
+ String geomWkt = rs.getString("geom_text");
+ if (geomWkt != null) {
+ geomWkt = geomWkt.replace("LINESTRING M (", "LINESTRING M(");
+ }
VesselTrack track = VesselTrack.builder()
.mmsi(mmsi)
.timeBucket(rs.getTimestamp("time_bucket").toLocalDateTime())
- .trackGeom(rs.getString("geom_text"))
+ .trackGeom(geomWkt)
.distanceNm(rs.getBigDecimal("distance_nm"))
.avgSpeed(rs.getBigDecimal("avg_speed"))
.maxSpeed(rs.getBigDecimal("max_speed"))
diff --git a/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedHourlyTrackReader.java b/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedHourlyTrackReader.java
index 86bd699..f080891 100644
--- a/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedHourlyTrackReader.java
+++ b/src/main/java/gc/mda/signal_batch/batch/reader/CacheBasedHourlyTrackReader.java
@@ -146,10 +146,15 @@ public class CacheBasedHourlyTrackReader implements ItemReader
|| (endPos == null && rs.getString("end_position") != null)) {
parseFailCount[0]++;
}
+ // ST_AsText()는 "LINESTRING M (...)" 공백 포함 반환 → 정규화
+ String geomWkt = rs.getString("geom_text");
+ if (geomWkt != null) {
+ geomWkt = geomWkt.replace("LINESTRING M (", "LINESTRING M(");
+ }
VesselTrack track = VesselTrack.builder()
.mmsi(mmsi)
.timeBucket(rs.getTimestamp("time_bucket").toLocalDateTime())
- .trackGeom(rs.getString("geom_text"))
+ .trackGeom(geomWkt)
.distanceNm(rs.getBigDecimal("distance_nm"))
.avgSpeed(rs.getBigDecimal("avg_speed"))
.maxSpeed(rs.getBigDecimal("max_speed"))
diff --git a/src/main/java/gc/mda/signal_batch/global/config/CacheWarmupService.java b/src/main/java/gc/mda/signal_batch/global/config/CacheWarmupService.java
index b4d61f3..255c8e6 100644
--- a/src/main/java/gc/mda/signal_batch/global/config/CacheWarmupService.java
+++ b/src/main/java/gc/mda/signal_batch/global/config/CacheWarmupService.java
@@ -169,10 +169,15 @@ public class CacheWarmupService {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
+ // ST_AsText()는 "LINESTRING M (...)" 공백 포함 반환 → Java 내부 형식으로 정규화
+ String geomWkt = rs.getString("track_geom");
+ if (geomWkt != null) {
+ geomWkt = geomWkt.replace("LINESTRING M (", "LINESTRING M(");
+ }
VesselTrack track = VesselTrack.builder()
.mmsi(rs.getString("mmsi"))
.timeBucket(rs.getTimestamp("time_bucket").toLocalDateTime())
- .trackGeom(rs.getString("track_geom"))
+ .trackGeom(geomWkt)
.distanceNm(BigDecimal.valueOf(rs.getDouble("distance_nm")))
.avgSpeed(BigDecimal.valueOf(rs.getDouble("avg_speed")))
.maxSpeed(BigDecimal.valueOf(rs.getDouble("max_speed")))
diff --git a/src/main/java/gc/mda/signal_batch/monitoring/controller/BatchAdminController.java b/src/main/java/gc/mda/signal_batch/monitoring/controller/BatchAdminController.java
index 3c81f6f..2925099 100644
--- a/src/main/java/gc/mda/signal_batch/monitoring/controller/BatchAdminController.java
+++ b/src/main/java/gc/mda/signal_batch/monitoring/controller/BatchAdminController.java
@@ -87,8 +87,11 @@ public class BatchAdminController {
.addString("endTime", end.withNano(0).toString())
.addLong("executionTime", System.currentTimeMillis());
- // vesselTrackAggregationJob의 경우 timeBucket 파라미터 추가
- if ("vesselTrackAggregationJob".equals(jobName)) {
+ // timeBucket 파라미터 추가 (vesselTrack: 5분 단위, daily: 일 시작)
+ if ("dailyAggregationJob".equals(jobName)) {
+ LocalDateTime timeBucket = start.toLocalDate().atStartOfDay();
+ paramsBuilder.addString("timeBucket", timeBucket.toString());
+ } else {
LocalDateTime timeBucket = start.withSecond(0).withNano(0)
.minusMinutes(start.getMinute() % 5);
paramsBuilder.addString("timeBucket", timeBucket.toString());