diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/MapSheetMngFileJobController.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/MapSheetMngFileJobController.java index c16c9d55..c5d0cebd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/MapSheetMngFileJobController.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/MapSheetMngFileJobController.java @@ -13,14 +13,19 @@ public class MapSheetMngFileJobController { private final MapSheetMngFileJobService mapSheetMngFileJobService; // 현재 상태 확인용 Getter - @Getter private boolean isSchedulerEnabled = false; - @Getter private boolean isFileSyncSchedulerEnabled = false; - @Getter private int mngSyncPageSize = 20; + @Getter + private boolean isSchedulerEnabled = false; + @Getter + private boolean isFileSyncSchedulerEnabled = false; + @Getter + private int mngSyncPageSize = 20; // 파일싱크 진행여부 확인하기 @Scheduled(fixedDelay = 1000 * 10) public void checkMngFileSync() { - if (!isSchedulerEnabled) return; + if (!isSchedulerEnabled) { + return; + } Integer mng = 0; // isFileSyncSchedulerEnabled = false; @@ -28,23 +33,25 @@ public class MapSheetMngFileJobController { mng = mapSheetMngFileJobService.checkMngFileSync(); this.isFileSyncSchedulerEnabled = true; System.out.println( - "MngFileSyncJob ON --> mngYyyy : " - + mng - + ", currentTime : " - + System.currentTimeMillis()); + "MngFileSyncJob --> mngYyyy : " + + mng + + ", currentTime : " + + System.currentTimeMillis()); } else { this.isFileSyncSchedulerEnabled = false; System.out.println( - "MngFileSyncJob OFF --> mngYyyy : " - + mng - + ", currentTime : " - + System.currentTimeMillis()); + "MngFileSyncJob --> mngYyyy : " + + mng + + ", currentTime : " + + System.currentTimeMillis()); } } @Scheduled(fixedDelay = 1000 * 10) public void mngFileSyncJob00() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 00 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(0, mngSyncPageSize); @@ -52,7 +59,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob01() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 01 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(1, mngSyncPageSize); @@ -60,7 +69,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob02() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 02 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(2, mngSyncPageSize); @@ -68,7 +79,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob03() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 03 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(3, mngSyncPageSize); @@ -76,7 +89,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob04() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 04 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(4, mngSyncPageSize); @@ -84,7 +99,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob05() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 05 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(5, mngSyncPageSize); @@ -92,7 +109,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob06() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 06 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(6, mngSyncPageSize); @@ -100,7 +119,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob07() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 07 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(7, mngSyncPageSize); @@ -108,7 +129,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob08() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 08 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(8, mngSyncPageSize); @@ -116,7 +139,9 @@ public class MapSheetMngFileJobController { @Scheduled(fixedDelay = 1000 * 5) public void mngFileSyncJob09() { - if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) return; + if (!isSchedulerEnabled || !isFileSyncSchedulerEnabled) { + return; + } System.out.println("mngFileSyncJob 09 Processing currentTime : " + System.currentTimeMillis()); mapSheetMngFileJobService.checkMapSheetFileProcess(9, mngSyncPageSize); diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON.md b/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON.md new file mode 100644 index 00000000..13b09115 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON.md @@ -0,0 +1,77 @@ +## 📌 학습데이터 라벨링 geojson 생성 + +### 🧩 사용하는 테이블 목록 + +- inference_results_testing : AI 수행 이후 변화탐지된 polygon insert 됨 +- tb_map_sheet_anal_inference : 추론 실행 완료 후, 추론 마스터 값 insert + - anal_state : 학습데이터 제작 상태 -> (enum) `LabelMngState` +- 💡 tb_map_sheet_anal_data_inference_geom 💡 : 추론 실행 완료 후, testing 값 insert +- tb_labeling_inspector : 라벨링 할당 시 선택한 검수자 insert + - 라벨링 할당 시 해당 회차별 검수자를 insert + - 매일 0시 스케줄링, 어제 라벨링 완료한 데이터 기준 검수 할당 진행 +- 💡 tb_labeling_assignment 💡 : 라벨링 할당 테이블 (polygon 수만큼) + - worker_uid : 라벨러 사번 + - inspector_uid : 검수자 사번 + - work_state : 라벨 진행 상태 -> (enum) `LabelState` + - inspect_state : 검수 진행 상태 -> (enum) `InspectState` + - work_stat_dttm : 라벨 상태 변경일시 + - inspect_stat_dttm : 검수 상태 변경일시 +- 💡 tb_map_sheet_learn_data_geom 💡 : 라벨링 툴에서 그린 polygon insert/update + - file_create_yn : geojson 파일 생성 후 true 로 업데이트 + +**💡표기된 테이블은 geo_uid (Long) 값으로 연결됨** + +### 🧩 스케줄링 로직 + +✅ 파일 위치 : TrainingDataReviewJobService.java + +#### 1. 라벨링 완료 건 검수 할당 + +- Method : assignReviewerYesterdayLabelComplete +- 매일 00시 00분 수행 (시간 변경 가능) +- 라벨링 상태 `work_state = DONE` +- 라벨링 상태 변경일시(work_stat_dttm) 기준 어제인 건 조회하여 할당 +- 실패 시, 수동 호출 API : `/api/training-data/review/run-schedule` + +#### 2. 학습데이터 geojson 생성 + +- Method : exportGeojsonLabelingGeom +- 매일 02시 00분 수행 (시간 변경 가능) +- 학습데이터 제작 상태가 `ING`인 회차 +- 어제까지 검수 상태 업데이트 된 polygon (`inspect_stat_dttm`) +- geojson 제작 대상은 누적으로 조회함 + - `inspect_state = 'COMPLETE'` + - `inspect_stat_dttm < 오늘 이전 모두` +- 파일 생성 후 polygon별 `file_create_yn = true` 로 업데이트 +- 회차에 할당된 polygon 총 개수(제외상태 빼고) = `file_create_yn = true` 인 개수가 맞을 때까지 스케줄링 진행 +- 실패 시, 수동 호출 API : `/api/training-data/review/run-label-geojson` +- 파일 생성 위치: `/kamco-nfs/model_output/labeling/` +- ️📚 생성 규칙 + +``` + /kamco-nfs/model_output/labeling/ + └─ {RESULT_UID} + └─{RESULT_UID 8자리}_{비교년도}_{기준년도}_{도엽번호}_D15.geojson + ``` + +### 🧩 사용 쿼리 + +- 📄 TRAINING_DATA_GEOJSON_QUERY.sql 참고 + +### 🧩 라벨링 툴 접속 가능한 계정 + +`* password : qwe123!@#` + +1. 라벨러 + +- 010222297501 +- 98765432 +- 20202020 +- 123456 +- 01022223333 + +2. 검수자 + +- 01022225555 +- 125511 +- K20251212001 diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON_QUERY.sql b/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON_QUERY.sql new file mode 100644 index 00000000..ff607831 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/TRAINING_DATA_GEOJSON_QUERY.sql @@ -0,0 +1,85 @@ +--1. 학습데이터 진행 중 회차 조회 +select lae1_0.anal_uid, + msle1_0.uid, + sum(case + when (lae1_0.inspect_state = 'UNCONFIRM' + or lae1_0.inspect_state = 'COMPLETE' + or lae1_0.inspect_state is null) + then 1 + else 0 + end), --allCnt + sum(case + when (lae1_0.inspect_state = 'COMPLETE') + then 1 + else 0 + end), --completeCnt + sum(case + when (msldge1_0.file_create_yn = true) + then 1 + else 0 + end) --fileCnt +from tb_labeling_assignment lae1_0 + join + tb_map_sheet_anal_inference msaie1_0 + on lae1_0.anal_uid = msaie1_0.anal_uid + and msaie1_0.anal_state = 'ING' --학습데이터 제작 진행중인 회차 + left join + tb_map_sheet_learn msle1_0 + on msaie1_0.learn_id = msle1_0.id + left join + tb_map_sheet_learn_data_geom msldge1_0 + on lae1_0.inference_geom_uid = msldge1_0.geo_uid --라벨링 할당 테이블과 geo_uid 가 같은 값으로 매핑되어 있음 +group by lae1_0.anal_uid, + msle1_0.uid +having sum(case + when (lae1_0.inspect_state = 'COMPLETE') + then 1 + else 0 + end) > 0 --검수할당 COMPLETE 상태가 있는 회차만 검색 +; + +--2. 해당 회차 + 어제까지 검수 완료된 도엽 조회 +select msaie1_0.compare_yyyy, + msaie1_0.target_yyyy, + lae1_0.assign_group_id +from tb_labeling_assignment lae1_0 + join + tb_map_sheet_anal_inference msaie1_0 + on lae1_0.anal_uid = msaie1_0.anal_uid +where lae1_0.anal_uid = 52 --해당 회차 + and lae1_0.inspect_state = 'COMPLETE' --검수 완료 상태 + and lae1_0.inspect_stat_dttm < '2026-01-23T00:00+09:00' --검수상태변경일 오늘 이전 모두 +group by msaie1_0.compare_yyyy, + msaie1_0.target_yyyy, + lae1_0.assign_group_id +; + +-- 3. 회차 + 도엽에 검수 완료된 polygon 조회 +select msldge1_0.geo_uid, + cast('Feature' as varchar), + st_asgeojson(msldge1_0.geom), + case + when (msldge1_0.class_after_cd in ('building', 'container')) + then cast('M1' as varchar) + when (msldge1_0.class_after_cd = 'waste') + then cast('M2' as varchar) + else 'M3' + end, + msldge1_0.class_before_cd, + msldge1_0.class_after_cd +from tb_labeling_assignment lae1_0 + left join + tb_map_sheet_learn_data_geom msldge1_0 --라벨링 그린 polygon 저장 테이블 + on lae1_0.inference_geom_uid = msldge1_0.geo_uid +where lae1_0.anal_uid = 52 + and lae1_0.assign_group_id = '34602060' + and lae1_0.inspect_state = 'COMPLETE' + and lae1_0.inspect_stat_dttm < '2026-01-23T00:00+09:00' +; + +--4. 파일 생성한 learn_data_geom 에 file_create_yn = true 로 업데이트 +update tb_map_sheet_learn_data_geom msldge1_0 +set file_create_yn= true, + updated_dttm='2026-01-23T19:27:28.623677700+09:00' +where msldge1_0.geo_uid = 390913 +;