label-to-review 로그 추가
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -33,7 +33,6 @@ public class TrainingDataLabelJobService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void runTask() {
|
public void runTask() {
|
||||||
// 프록시를 통해 호출해야 @Transactional이 적용됨
|
|
||||||
applicationContext
|
applicationContext
|
||||||
.getBean(TrainingDataLabelJobService.class)
|
.getBean(TrainingDataLabelJobService.class)
|
||||||
.assignReviewerYesterdayLabelComplete(null);
|
.assignReviewerYesterdayLabelComplete(null);
|
||||||
@@ -42,87 +41,136 @@ public class TrainingDataLabelJobService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void assignReviewerYesterdayLabelComplete(LocalDate baseDate) {
|
public void assignReviewerYesterdayLabelComplete(LocalDate baseDate) {
|
||||||
|
|
||||||
|
long jobStart = System.currentTimeMillis();
|
||||||
|
log.info("[JOB-START] TrainingDataLabelJob start profile={}", profile);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info("[Step 1-1] 라벨링 완료된 데이터 목록 조회한다.");
|
|
||||||
log.info("=== baseDate : {}", baseDate);
|
log.info("[Step 1-1] 라벨링 완료된 데이터 조회 시작 baseDate={}", baseDate);
|
||||||
log.info("=== baseDate 있으면 해당 일자, 없으면 어제일자로 조회");
|
|
||||||
List<Tasks> tasks =
|
List<Tasks> tasks =
|
||||||
trainingDataLabelJobCoreService.findCompletedYesterdayUnassigned(baseDate);
|
trainingDataLabelJobCoreService.findCompletedYesterdayUnassigned(baseDate);
|
||||||
|
|
||||||
log.info("[Step 1-2] 목록 객체 건수 count : {}", tasks == null ? 0 : tasks.size());
|
int totalTasks = tasks == null ? 0 : tasks.size();
|
||||||
if (tasks.isEmpty()) {
|
|
||||||
log.info("[Step 1-3] 조회된 것 없어 return");
|
log.info("[Step 1-2] 조회된 작업 건수={}", totalTasks);
|
||||||
|
|
||||||
|
if (tasks == null || tasks.isEmpty()) {
|
||||||
|
log.info("[Step 1-3] 조회된 데이터 없음 → 종료");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 회차별로 그룹핑
|
log.info("[Step 2-1] 회차별 그룹핑 시작");
|
||||||
log.info("[Step 2-1] 회차별로 그룹핑 시작");
|
|
||||||
Map<Long, List<Tasks>> taskByRound =
|
Map<Long, List<Tasks>> taskByRound =
|
||||||
tasks.stream().collect(Collectors.groupingBy(Tasks::getAnalUid));
|
tasks.stream().collect(Collectors.groupingBy(Tasks::getAnalUid));
|
||||||
|
|
||||||
// 회차별 분배
|
log.info("[Step 2-2] 회차 수={}", taskByRound.size());
|
||||||
log.info("[Step 3-1] 회차별로 분배 시작");
|
|
||||||
|
int successRound = 0;
|
||||||
|
int skipRound = 0;
|
||||||
|
|
||||||
for (Map.Entry<Long, List<Tasks>> entry : taskByRound.entrySet()) {
|
for (Map.Entry<Long, List<Tasks>> entry : taskByRound.entrySet()) {
|
||||||
|
|
||||||
|
long roundStart = System.currentTimeMillis();
|
||||||
|
|
||||||
Long analUid = entry.getKey();
|
Long analUid = entry.getKey();
|
||||||
List<Tasks> analTasks = entry.getValue();
|
List<Tasks> analTasks = entry.getValue();
|
||||||
|
|
||||||
// pending 계산
|
log.info(
|
||||||
log.info("[Step 3-2] 수행하는 회차 analUid: {}", analUid);
|
"[ROUND-START] analUid={} tasks={}", analUid, analTasks == null ? 0 : analTasks.size());
|
||||||
log.info("해당 회차에 라벨링 할당받은 검수자별 완료 건수 count(), 완료한 게 적은 순으로 해야 일이 한 사람에게 몰리지 않음");
|
|
||||||
|
log.info("[Step 3-2] 해당 회차 검수자 pending 조회");
|
||||||
|
|
||||||
List<InspectorPendingDto> pendings =
|
List<InspectorPendingDto> pendings =
|
||||||
trainingDataLabelJobCoreService.findInspectorPendingByRound(analUid);
|
trainingDataLabelJobCoreService.findInspectorPendingByRound(analUid);
|
||||||
|
|
||||||
log.info("검수자 수: {}", pendings == null ? 0 : pendings.size());
|
int reviewerCount = pendings == null ? 0 : pendings.size();
|
||||||
if (pendings.isEmpty()) {
|
|
||||||
log.info("[Step 3-3] 할당된 검수자가 없으면 return");
|
log.info("[Step 3-3] 검수자 수={}", reviewerCount);
|
||||||
|
|
||||||
|
if (pendings == null || pendings.isEmpty()) {
|
||||||
|
log.warn("[ROUND-SKIP] 검수자 없음 analUid={}", analUid);
|
||||||
|
skipRound++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("[Step 4-1] 검수자 사번 List 생성");
|
|
||||||
List<String> reviewerIds =
|
List<String> reviewerIds =
|
||||||
pendings.stream().map(InspectorPendingDto::getInspectorUid).toList();
|
pendings.stream().map(InspectorPendingDto::getInspectorUid).toList();
|
||||||
|
|
||||||
// Lock 걸릴 수 있기 때문에 엔티티 조회하는 Repository 에서 구현
|
log.info("[Step 4-1] 검수자 목록={}", reviewerIds);
|
||||||
log.info("[Step 4-2] 검수자 테이블 lock 걸리지 않게 처리");
|
|
||||||
|
log.info("[Step 4-2] 검수자 row lock 수행");
|
||||||
|
|
||||||
trainingDataLabelJobCoreService.lockInspectors(analUid, reviewerIds);
|
trainingDataLabelJobCoreService.lockInspectors(analUid, reviewerIds);
|
||||||
|
|
||||||
// 균등 분배
|
log.info("[Step 5-1] 라벨 작업 균등 분배 시작");
|
||||||
log.info("[Step 5-1] 검수자에게 라벨 작업 균등분배 시작");
|
|
||||||
Map<String, List<Tasks>> assignMap = distributeByLeastPending(analTasks, reviewerIds);
|
Map<String, List<Tasks>> assignMap = distributeByLeastPending(analTasks, reviewerIds);
|
||||||
log.info("[Step 5-2] 검수자에게 라벨 작업 균등분배 완료");
|
|
||||||
|
log.info("[Step 5-2] 라벨 작업 균등 분배 완료");
|
||||||
|
|
||||||
|
assignMap.forEach(
|
||||||
|
(reviewerId, assignedTasks) ->
|
||||||
|
log.info(
|
||||||
|
"[Step 5-3] reviewerId={} assignedCount={}",
|
||||||
|
reviewerId,
|
||||||
|
assignedTasks == null ? 0 : assignedTasks.size()));
|
||||||
|
|
||||||
|
log.info("[Step 5-4] reviewer batch update 시작");
|
||||||
|
|
||||||
// reviewer별 batch update
|
|
||||||
log.info("[Step 5-3] 검수자별 할당 데이터를 batch update 시작");
|
|
||||||
assignMap.forEach(
|
assignMap.forEach(
|
||||||
(reviewerId, assignedTasks) -> {
|
(reviewerId, assignedTasks) -> {
|
||||||
if (assignedTasks.isEmpty()) {
|
if (assignedTasks == null || assignedTasks.isEmpty()) {
|
||||||
log.info("[Step 5-4] 할당된 데이터 없으면 return");
|
log.debug("[Step 5-5] reviewer={} 할당 없음", reviewerId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UUID> assignmentUids =
|
List<UUID> assignmentUids =
|
||||||
assignedTasks.stream().map(Tasks::getAssignmentUid).toList();
|
assignedTasks.stream().map(Tasks::getAssignmentUid).toList();
|
||||||
log.info("[Step 6-1] 할당 작업에 검수자 아이디 update");
|
|
||||||
log.info("==== 검수자 사번: {}", reviewerId);
|
log.info(
|
||||||
log.info("==== 할당 갯수: {}", assignmentUids == null ? 0 : assignmentUids.size());
|
"[Step 6-1] reviewer assignment update reviewerId={}, count={}",
|
||||||
|
reviewerId,
|
||||||
|
assignmentUids.size());
|
||||||
|
|
||||||
trainingDataLabelJobCoreService.assignReviewerBatch(assignmentUids, reviewerId);
|
trainingDataLabelJobCoreService.assignReviewerBatch(assignmentUids, reviewerId);
|
||||||
|
|
||||||
log.info("[Step 7-1] geom 테이블에 검수 상태 update");
|
|
||||||
List<Long> geomUids = assignedTasks.stream().map(Tasks::getInferenceUid).toList();
|
List<Long> geomUids = assignedTasks.stream().map(Tasks::getInferenceUid).toList();
|
||||||
|
|
||||||
|
log.info("[Step 7-1] geom 상태 업데이트 geomCount={}", geomUids.size());
|
||||||
|
|
||||||
trainingDataLabelJobCoreService.updateGeomUidTestState(geomUids);
|
trainingDataLabelJobCoreService.updateGeomUidTestState(geomUids);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
successRound++;
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"[ROUND-END] analUid={} elapsed={}ms",
|
||||||
|
analUid,
|
||||||
|
System.currentTimeMillis() - roundStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"[JOB-SUMMARY] rounds={}, successRounds={}, skipRounds={}, elapsed={}ms",
|
||||||
|
taskByRound.size(),
|
||||||
|
successRound,
|
||||||
|
skipRound,
|
||||||
|
System.currentTimeMillis() - jobStart);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("배치 처리 중 예외", e);
|
|
||||||
|
log.error("[JOB-ERROR] 배치 처리 중 예외 발생", e);
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, List<Tasks>> distributeByLeastPending(
|
private Map<String, List<Tasks>> distributeByLeastPending(
|
||||||
List<Tasks> tasks, List<String> reviewerIds) {
|
List<Tasks> tasks, List<String> reviewerIds) {
|
||||||
|
|
||||||
Map<String, List<Tasks>> result = new LinkedHashMap<>();
|
Map<String, List<Tasks>> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
// 순서 유지 중요 (ASC 정렬된 상태)
|
|
||||||
for (String reviewerId : reviewerIds) {
|
for (String reviewerId : reviewerIds) {
|
||||||
result.put(reviewerId, new ArrayList<>());
|
result.put(reviewerId, new ArrayList<>());
|
||||||
}
|
}
|
||||||
@@ -130,7 +178,9 @@ public class TrainingDataLabelJobService {
|
|||||||
int reviewerCount = reviewerIds.size();
|
int reviewerCount = reviewerIds.size();
|
||||||
|
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < tasks.size(); i++) {
|
||||||
|
|
||||||
String reviewerId = reviewerIds.get(i % reviewerCount);
|
String reviewerId = reviewerIds.get(i % reviewerCount);
|
||||||
|
|
||||||
result.get(reviewerId).add(tasks.get(i));
|
result.get(reviewerId).add(tasks.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user