From 4bed98dbc864e815f02bd49dd304ccd1df471320 Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Thu, 5 Mar 2026 11:09:56 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=8A=A4=ED=82=A4=EB=A7=88=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(t=5Fstd=5Fsnp=5Fdata=20=E2=86=92=20std=5F?= =?UTF-8?q?snp=5Fdata,=20t=5Fstd=5Fsnp=5Fsvc=20=E2=86=92=20std=5Fsnp=5Fsvc?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 2 +- sql/chnprmship-cache-diag.sql | 24 +++++++++---------- .../snp/batch/global/model/BatchApiLog.java | 2 +- .../batch/global/model/BatchFailedRecord.java | 2 +- .../global/partition/PartitionConfig.java | 6 ++--- .../batch/entity/AisTargetEntity.java | 2 +- .../classifier/Core20Properties.java | 16 ++++++------- src/main/resources/application-dev.yml | 10 ++++---- src/main/resources/application-prod.yml | 10 ++++---- src/main/resources/application.yml | 14 +++++------ src/main/resources/sql/ais_target_ddl.sql | 6 ++--- src/main/resources/sql/old_job_cleanup.sql | 2 +- 12 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4b0d89d..6d522ba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ ## 기술 스택 - Java 17, Spring Boot 3.2.1, Spring Batch 5.1.0 -- PostgreSQL (스키마: t_std_snp_data) +- PostgreSQL (스키마: std_snp_data) - Quartz Scheduler (JDBC Store) - Spring Kafka (AIS Target → Kafka 파이프라인) - WebFlux WebClient (외부 API 호출) diff --git a/sql/chnprmship-cache-diag.sql b/sql/chnprmship-cache-diag.sql index 716f1cd..4f4c2d9 100644 --- a/sql/chnprmship-cache-diag.sql +++ b/sql/chnprmship-cache-diag.sql @@ -1,6 +1,6 @@ -- ============================================================ -- ChnPrmShip 캐시 검증 진단 쿼리 --- 대상: t_std_snp_data.ais_target (일별 파티션) +-- 대상: std_snp_data.ais_target (일별 파티션) -- 목적: 최근 2일 내 대상 MMSI별 최종위치 캐싱 검증 -- ============================================================ @@ -22,7 +22,7 @@ SELECT (SELECT COUNT(*) FROM tmp_chn_mmsi) - COUNT(DISTINCT a.mmsi) AS mmsi_without_data_2d, ROUND(COUNT(DISTINCT a.mmsi) * 100.0 / NULLIF((SELECT COUNT(*) FROM tmp_chn_mmsi), 0), 1) AS hit_rate_pct -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '2 days'; @@ -37,7 +37,7 @@ SELECT COUNT(*) AS cached_count, NOW() - MAX(message_timestamp) AS newest_age FROM ( SELECT DISTINCT ON (a.mmsi) a.mmsi, a.message_timestamp - FROM t_std_snp_data.ais_target a + FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '2 days' ORDER BY a.mmsi, a.message_timestamp DESC @@ -58,7 +58,7 @@ SELECT DISTINCT ON (a.mmsi) a.cog, a.heading, NOW() - a.message_timestamp AS data_age -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '2 days' ORDER BY a.mmsi, a.message_timestamp DESC @@ -72,7 +72,7 @@ SELECT t.mmsi AS missing_mmsi FROM tmp_chn_mmsi t LEFT JOIN ( SELECT DISTINCT mmsi - FROM t_std_snp_data.ais_target + FROM std_snp_data.ais_target WHERE mmsi IN (SELECT mmsi FROM tmp_chn_mmsi) AND message_timestamp >= NOW() - INTERVAL '2 days' ) a ON t.mmsi = a.mmsi @@ -86,31 +86,31 @@ ORDER BY t.mmsi; SELECT '6시간 이내' AS time_range, COUNT(DISTINCT mmsi) AS distinct_mmsi -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '6 hours' UNION ALL SELECT '12시간 이내', COUNT(DISTINCT mmsi) -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '12 hours' UNION ALL SELECT '1일 이내', COUNT(DISTINCT mmsi) -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '1 day' UNION ALL SELECT '2일 이내', COUNT(DISTINCT mmsi) -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi WHERE a.message_timestamp >= NOW() - INTERVAL '2 days' UNION ALL SELECT '전체(무제한)', COUNT(DISTINCT mmsi) -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi; @@ -123,7 +123,7 @@ SELECT COUNT(DISTINCT mmsi) AS distinct_mmsi, MIN(message_timestamp) AS min_ts, MAX(message_timestamp) AS max_ts -FROM t_std_snp_data.ais_target a +FROM std_snp_data.ais_target a JOIN tmp_chn_mmsi t ON a.mmsi = t.mmsi GROUP BY tableoid::regclass ORDER BY max_ts DESC; @@ -139,7 +139,7 @@ SELECT FROM pg_inherits i JOIN pg_class c ON c.oid = i.inhrelid JOIN pg_stat_user_tables s ON s.relid = c.oid -WHERE i.inhparent = 't_std_snp_data.ais_target'::regclass +WHERE i.inhparent = 'std_snp_data.ais_target'::regclass ORDER BY c.relname DESC; diff --git a/src/main/java/com/snp/batch/global/model/BatchApiLog.java b/src/main/java/com/snp/batch/global/model/BatchApiLog.java index cdd03a0..2b124e3 100644 --- a/src/main/java/com/snp/batch/global/model/BatchApiLog.java +++ b/src/main/java/com/snp/batch/global/model/BatchApiLog.java @@ -7,7 +7,7 @@ import org.hibernate.annotations.CreationTimestamp; import java.time.LocalDateTime; @Entity -@Table(name = "batch_api_log", schema = "t_std_snp_data") +@Table(name = "batch_api_log", schema = "std_snp_data") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor diff --git a/src/main/java/com/snp/batch/global/model/BatchFailedRecord.java b/src/main/java/com/snp/batch/global/model/BatchFailedRecord.java index 8fd38cf..de5610c 100644 --- a/src/main/java/com/snp/batch/global/model/BatchFailedRecord.java +++ b/src/main/java/com/snp/batch/global/model/BatchFailedRecord.java @@ -7,7 +7,7 @@ import org.hibernate.annotations.CreationTimestamp; import java.time.LocalDateTime; @Entity -@Table(name = "batch_failed_record", schema = "t_std_snp_data") +@Table(name = "batch_failed_record", schema = "std_snp_data") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor diff --git a/src/main/java/com/snp/batch/global/partition/PartitionConfig.java b/src/main/java/com/snp/batch/global/partition/PartitionConfig.java index 33fc195..7c4f6c5 100644 --- a/src/main/java/com/snp/batch/global/partition/PartitionConfig.java +++ b/src/main/java/com/snp/batch/global/partition/PartitionConfig.java @@ -15,12 +15,12 @@ import java.util.Optional; * 설정 예시: * app.batch.partition: * daily-tables: - * - schema: snp_data + * - schema: std_snp_data * table-name: ais_target * partition-column: message_timestamp * periods-ahead: 3 * monthly-tables: - * - schema: snp_data + * - schema: std_snp_data * table-name: some_table * partition-column: created_at * periods-ahead: 2 @@ -58,7 +58,7 @@ public class PartitionConfig { @Getter @Setter public static class PartitionTableConfig { - private String schema = "snp_data"; + private String schema = "std_snp_data"; private String tableName; private String partitionColumn; private int periodsAhead = 3; // 미리 생성할 기간 수 (daily: 일, monthly: 월) diff --git a/src/main/java/com/snp/batch/jobs/aistarget/batch/entity/AisTargetEntity.java b/src/main/java/com/snp/batch/jobs/aistarget/batch/entity/AisTargetEntity.java index 27aa694..709254d 100644 --- a/src/main/java/com/snp/batch/jobs/aistarget/batch/entity/AisTargetEntity.java +++ b/src/main/java/com/snp/batch/jobs/aistarget/batch/entity/AisTargetEntity.java @@ -13,7 +13,7 @@ import java.time.OffsetDateTime; /** * AIS Target Entity * - * 테이블: snp_data.ais_target + * 테이블: std_snp_data.ais_target * PK: mmsi + message_timestamp (복합키) * * 용도: diff --git a/src/main/java/com/snp/batch/jobs/aistarget/classifier/Core20Properties.java b/src/main/java/com/snp/batch/jobs/aistarget/classifier/Core20Properties.java index 1e1eb3f..fc3f06e 100644 --- a/src/main/java/com/snp/batch/jobs/aistarget/classifier/Core20Properties.java +++ b/src/main/java/com/snp/batch/jobs/aistarget/classifier/Core20Properties.java @@ -13,8 +13,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * 프로파일별 설정 파일에서 지정할 수 있도록 구성 * * 사용 예: - * - dev: snp_data.core20 (ihslrorimoshipno, maritimemobileserviceidentitymmsinumber) - * - prod: new_snp.core20 (lrno, mmsi) + * - dev: std_snp_svc.tb_ship_main_info (imo_no, mmsi_no) + * - prod: std_snp_svc.tb_ship_main_info (imo_no, mmsi_no) */ @Slf4j @Getter @@ -23,24 +23,24 @@ import org.springframework.boot.context.properties.ConfigurationProperties; public class Core20Properties { /** - * 스키마명 (예: snp_data, new_snp) + * 스키마명 (예: std_snp_svc) */ - private String schema = "snp_data"; + private String schema = "std_snp_svc"; /** - * 테이블명 (예: core20) + * 테이블명 (예: tb_ship_main_info) */ - private String table = "core20"; + private String table = "tb_ship_main_info"; /** * IMO/LRNO 컬럼명 (PK, NOT NULL) */ - private String imoColumn = "ihslrorimoshipno"; + private String imoColumn = "imo_no"; /** * MMSI 컬럼명 (NULLABLE) */ - private String mmsiColumn = "maritimemobileserviceidentitymmsinumber"; + private String mmsiColumn = "mmsi_no"; /** * 전체 테이블명 반환 (schema.table) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index dc657be..4b7a934 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -22,12 +22,12 @@ spring: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true - default_schema: t_std_snp_data + default_schema: std_snp_data # Batch Configuration batch: jdbc: - table-prefix: "t_std_snp_data.batch_" + table-prefix: "std_snp_data.batch_" initialize-schema: always # Changed to 'never' as tables already exist job: enabled: false # Prevent auto-run on startup @@ -49,7 +49,7 @@ spring: org.quartz.threadPool.threadCount: 10 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate - org.quartz.jobStore.tablePrefix: t_std_snp_data.QRTZ_ + org.quartz.jobStore.tablePrefix: std_snp_data.QRTZ_ org.quartz.jobStore.isClustered: false org.quartz.jobStore.misfireThreshold: 60000 @@ -142,7 +142,7 @@ app: # Core20 캐시 테이블 설정 (환경별로 테이블/컬럼명이 다를 수 있음) core20: - schema: t_std_snp_svc # 스키마명 + schema: std_snp_svc # 스키마명 table: tb_ship_main_info # 테이블명 imo-column: imo_no # IMO/LRNO 컬럼명 (PK, NOT NULL) mmsi-column: mmsi_no # MMSI 컬럼명 (NULLABLE) @@ -151,7 +151,7 @@ app: partition: # 일별 파티션 테이블 목록 (네이밍: {table}_YYMMDD) daily-tables: - - schema: t_std_snp_data + - schema: std_snp_data table-name: ais_target partition-column: message_timestamp periods-ahead: 3 # 미리 생성할 일수 diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index b718ed1..e449034 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -22,12 +22,12 @@ spring: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true - default_schema: t_std_snp_data + default_schema: std_snp_data # Batch Configuration batch: jdbc: - table-prefix: "t_std_snp_data.batch_" + table-prefix: "std_snp_data.batch_" initialize-schema: never # Changed to 'never' as tables already exist job: enabled: false # Prevent auto-run on startup @@ -49,7 +49,7 @@ spring: org.quartz.threadPool.threadCount: 10 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate - org.quartz.jobStore.tablePrefix: t_std_snp_data.QRTZ_ + org.quartz.jobStore.tablePrefix: std_snp_data.QRTZ_ org.quartz.jobStore.isClustered: false org.quartz.jobStore.misfireThreshold: 60000 @@ -144,7 +144,7 @@ app: # Core20 캐시 테이블 설정 (환경별로 테이블/컬럼명이 다를 수 있음) core20: - schema: t_std_snp_svc # 스키마명 + schema: std_snp_svc # 스키마명 table: tb_ship_main_info # 테이블명 imo-column: imo_no # IMO/LRNO 컬럼명 (PK, NOT NULL) mmsi-column: mmsi_no # MMSI 컬럼명 (NULLABLE) @@ -153,7 +153,7 @@ app: partition: # 일별 파티션 테이블 목록 (네이밍: {table}_YYMMDD) daily-tables: - - schema: t_std_snp_data + - schema: std_snp_data table-name: ais_target partition-column: message_timestamp periods-ahead: 3 # 미리 생성할 일수 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6180885..d9898af 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,12 +22,12 @@ spring: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true - default_schema: t_std_snp_data + default_schema: std_snp_data # Batch Configuration batch: jdbc: - table-prefix: "t_std_snp_data.batch_" + table-prefix: "std_snp_data.batch_" initialize-schema: never # Changed to 'never' as tables already exist job: enabled: false # Prevent auto-run on startup @@ -49,7 +49,7 @@ spring: org.quartz.threadPool.threadCount: 10 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate - org.quartz.jobStore.tablePrefix: t_std_snp_data.QRTZ_ + org.quartz.jobStore.tablePrefix: std_snp_data.QRTZ_ org.quartz.jobStore.isClustered: false org.quartz.jobStore.misfireThreshold: 60000 @@ -95,7 +95,7 @@ app: batch: chunk-size: 1000 target-schema: - name: t_std_snp_data + name: std_snp_data tables: ship-001: tb_ship_default_info ship-002: tb_ship_info_mst @@ -147,7 +147,7 @@ app: risk-compliance-003: tb_company_compliance_info ship-028: ship_detail_hash_json service-schema: - name: t_std_snp_svc + name: std_snp_svc tables: service-001: tb_ship_main_info api: @@ -212,7 +212,7 @@ app: # Core20 캐시 테이블 설정 (환경별로 테이블/컬럼명이 다를 수 있음) core20: - schema: t_std_snp_svc # 스키마명 + schema: std_snp_svc # 스키마명 table: tb_ship_main_info # 테이블명 imo-column: imo_no # IMO/LRNO 컬럼명 (PK, NOT NULL) mmsi-column: mmsi_no # MMSI 컬럼명 (NULLABLE) @@ -221,7 +221,7 @@ app: partition: # 일별 파티션 테이블 목록 (네이밍: {table}_YYMMDD) daily-tables: - - schema: t_std_snp_data + - schema: std_snp_data table-name: ais_target partition-column: message_timestamp periods-ahead: 3 # 미리 생성할 일수 diff --git a/src/main/resources/sql/ais_target_ddl.sql b/src/main/resources/sql/ais_target_ddl.sql index 6dc417d..1d76dd8 100644 --- a/src/main/resources/sql/ais_target_ddl.sql +++ b/src/main/resources/sql/ais_target_ddl.sql @@ -154,7 +154,7 @@ BEGIN RETURN EXISTS ( SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = 'snp_data' + WHERE n.nspname = 'std_snp_data' AND c.relname = partition_name AND c.relkind = 'r' ); @@ -261,7 +261,7 @@ BEGIN FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace JOIN pg_inherits i ON i.inhrelid = c.oid - WHERE n.nspname = 'snp_data' + WHERE n.nspname = 'std_snp_data' AND c.relname LIKE 'ais_target_%' AND LENGTH(c.relname) = 17 -- ais_target_YYMMDD = 17자 AND c.relkind = 'r' @@ -304,7 +304,7 @@ BEGIN FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace JOIN pg_inherits i ON i.inhrelid = c.oid - WHERE n.nspname = 'snp_data' + WHERE n.nspname = 'std_snp_data' AND c.relname LIKE 'ais_target_%' AND c.relkind = 'r' ORDER BY c.relname; diff --git a/src/main/resources/sql/old_job_cleanup.sql b/src/main/resources/sql/old_job_cleanup.sql index 64e4327..227afdc 100644 --- a/src/main/resources/sql/old_job_cleanup.sql +++ b/src/main/resources/sql/old_job_cleanup.sql @@ -1,5 +1,5 @@ -- 오래된 STARTED 상태 Job을 정리하는 SQL 쿼리입니다. --- snp_data 스키마에 batch_ 접두사를 사용하는 예시입니다. 실제 스키마에 맞추어 수정해서 사용하세요. +-- std_snp_data 스키마에 batch_ 접두사를 사용하는 예시입니다. 실제 스키마에 맞추어 수정해서 사용하세요. -- 참고: 시간 간격 변경이 필요하면 INTERVAL '2 hours' 부분을 수정하세요: -- 1시간: INTERVAL '1 hour' -- 2.45.2