diff --git a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java index 161b1c11..bff7b299 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java @@ -463,7 +463,8 @@ public class GlobalExceptionHandler { String stackTraceStr = Arrays.stream(stackTrace) .map(StackTraceElement::toString) - .collect(Collectors.joining("\n")); + .collect(Collectors.joining("\n")) + .substring(0, 255); ErrorLogEntity errorLogEntity = new ErrorLogEntity( diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java index 8f53ccbf..9e359a82 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -3,8 +3,7 @@ package com.kamco.cd.kamcoback.label; import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; -import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector; -import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse; import com.kamco.cd.kamcoback.label.service.LabelAllocateService; import io.swagger.v3.oas.annotations.Operation; @@ -69,7 +68,7 @@ public class LabelAllocateApiController { }) @GetMapping("/avail-user") public ApiResponseDto> availUserList( - @Parameter(description = "사용자 역할 (LABELER: 라벨러, INSPECTOR: 검수자)", example = "LABELER") + @Parameter(description = "사용자 역할 (LABELER: 라벨러, REVIEWER: 검수자)", example = "LABELER") @RequestParam @Schema() String role) { @@ -78,10 +77,9 @@ public class LabelAllocateApiController { @Operation( summary = "작업자 목록 및 3일치 통계 조회", - description = - """ - 학습데이터 제작 현황 조회 API입니다. - """) + description = """ + 학습데이터 제작 현황 조회 API입니다. + """) @ApiResponses( value = { @ApiResponse( @@ -97,93 +95,93 @@ public class LabelAllocateApiController { description = "라벨러 작업자들의 통계 정보", value = """ - { - "data": { - "progressInfo": { - "labelingProgressRate": 79.34, - "workStatus": "진행중", - "completedCount": 6554, - "totalAssignedCount": 8258, - "labelerCount": 5, - "remainingLabelCount": 1704, - "inspectorCount": 3, - "remainingInspectCount": 890 - }, - "workers": [ - { - "workerId": "1234567", - "workerName": "김라벨", - "workerType": "LABELER", - "totalAssigned": 1500, - "completed": 1100, - "skipped": 50, - "remaining": 350, - "history": { - "day1Ago": 281, - "day2Ago": 302, - "day3Ago": 294, - "average": 292 - }, - "isStagnated": false + { + "data": { + "progressInfo": { + "labelingProgressRate": 79.34, + "workStatus": "진행중", + "completedCount": 6554, + "totalAssignedCount": 8258, + "labelerCount": 5, + "remainingLabelCount": 1704, + "inspectorCount": 3, + "remainingInspectCount": 890 }, - { - "workerId": "2345678", - "workerName": "이작업", - "workerType": "LABELER", - "totalAssigned": 2000, - "completed": 1850, - "skipped": 100, - "remaining": 50, - "history": { - "day1Ago": 5, - "day2Ago": 3, - "day3Ago": 8, - "average": 5 + "workers": [ + { + "workerId": "1234567", + "workerName": "김라벨", + "workerType": "LABELER", + "totalAssigned": 1500, + "completed": 1100, + "skipped": 50, + "remaining": 350, + "history": { + "day1Ago": 281, + "day2Ago": 302, + "day3Ago": 294, + "average": 292 + }, + "isStagnated": false }, - "isStagnated": true - } - ] + { + "workerId": "2345678", + "workerName": "이작업", + "workerType": "LABELER", + "totalAssigned": 2000, + "completed": 1850, + "skipped": 100, + "remaining": 50, + "history": { + "day1Ago": 5, + "day2Ago": 3, + "day3Ago": 8, + "average": 5 + }, + "isStagnated": true + } + ] + } } - } - """), + """), @ExampleObject( name = "검수자 조회 예시", description = "검수자 작업자들의 통계 정보", value = """ - { - "data": { - "progressInfo": { - "labelingProgressRate": 79.34, - "workStatus": "진행중", - "completedCount": 6554, - "totalAssignedCount": 8258, - "labelerCount": 5, - "remainingLabelCount": 1704, - "inspectorCount": 3, - "remainingInspectCount": 890 - }, - "workers": [ - { - "workerId": "9876543", - "workerName": "박검수", - "workerType": "INSPECTOR", - "totalAssigned": 1200, - "completed": 980, - "skipped": 20, - "remaining": 200, - "history": { - "day1Ago": 150, - "day2Ago": 145, - "day3Ago": 155, - "average": 150 - }, - "isStagnated": false - } - ] + { + "data": { + "progressInfo": { + "labelingProgressRate": 79.34, + "workStatus": "진행중", + "completedCount": 6554, + "totalAssignedCount": 8258, + "labelerCount": 5, + "remainingLabelCount": 1704, + "inspectorCount": 3, + "remainingInspectCount": 890 + }, + "workers": [ + { + "workerId": "9876543", + "workerName": "박검수", + "workerType": "REVIEWER", + "totalAssigned": 1200, + "completed": 980, + "skipped": 20, + "remaining": 200, + "history": { + "day1Ago": 150, + "day2Ago": 145, + "day3Ago": 155, + "average": 150 + }, + "isStagnated": false + } + ] + } } - } - """) + """) })), @ApiResponse( responseCode = "404", @@ -227,7 +225,7 @@ public class LabelAllocateApiController { example = "LABELER", schema = @Schema( - allowableValues = {"LABELER", "INSPECTOR"}, + allowableValues = {"LABELER", "REVIEWER"}, defaultValue = "LABELER")) @RequestParam(required = false) String type, @@ -259,22 +257,40 @@ public class LabelAllocateApiController { analUid, workerType, searchName, searchEmployeeNo, sort)); } - // 라벨링 수량 할당하는 로직 테스트 + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @PostMapping("/allocate") - public ApiResponseDto labelAllocate(@RequestBody LabelAllocateDto dto) { + public ApiResponseDto labelAllocate( + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "라벨링 수량 할당", + required = true, + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = LabelAllocateDto.AllocateDto.class))) + @RequestBody + LabelAllocateDto.AllocateDto dto) + throws Exception { - List targets = - List.of( - new TargetUser("1234567", 1000), - new TargetUser("2345678", 400), - new TargetUser("3456789", 440)); - List inspectors = - List.of( - new TargetInspector("9876543", 1000), - new TargetInspector("8765432", 340), - new TargetInspector("98765432", 500)); - labelAllocateService.allocateAsc(targets, inspectors); + labelAllocateService.allocateAsc( + dto.getAutoType(), dto.getStage(), dto.getLabelers(), dto.getInspectors()); return ApiResponseDto.ok(null); } + + @GetMapping + public ApiResponseDto findInferenceDetail(@RequestParam Long analUid) { + return ApiResponseDto.ok(labelAllocateService.findInferenceDetail(analUid)); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java index d1705e92..5b508a07 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java @@ -2,7 +2,9 @@ package com.kamco.cd.kamcoback.label.dto; import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose; import com.kamco.cd.kamcoback.common.utils.enums.EnumType; +import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; +import java.util.List; import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Getter; @@ -78,10 +80,31 @@ public class LabelAllocateDto { } } + @Getter + @Setter + @AllArgsConstructor + public static class AllocateDto { + + @Schema(description = "자동/수동여부(AUTO/MANUAL)", example = "AUTO") + private String autoType; + + @Schema(description = "회차", example = "4") + private Integer stage; + + @Schema(description = "라벨러 할당 목록") + private List labelers; + + @Schema(description = "검수자 할당 목록") + private List inspectors; + } + @Getter public static class TargetUser { + @Schema(description = "라벨러 사번", example = "labeler44") private final String userId; + + @Schema(description = "할당 건수", example = "200") private final int demand; public TargetUser(String userId, int demand) { @@ -94,7 +117,10 @@ public class LabelAllocateDto { @AllArgsConstructor public static class TargetInspector { + @Schema(description = "검수자 사번", example = "K20251212001") private final String inspectorUid; + + @Schema(description = "할당 명수", example = "3") private int userCount; } @@ -125,4 +151,17 @@ public class LabelAllocateDto { private String employeeNo; private String name; } + + @Getter + @Setter + @AllArgsConstructor + public static class InferenceDetail { + + private String analTitle; + private Integer stage; + private ZonedDateTime gukyuinDttm; + private Long count; + private Long labelCnt; + private Long inspectorCnt; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java index 98fd7a70..a51a2ae7 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -1,6 +1,7 @@ package com.kamco.cd.kamcoback.label.service; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; @@ -10,7 +11,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService; import java.time.LocalDate; import java.util.List; -import java.util.Objects; +import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -29,57 +30,56 @@ public class LabelAllocateService { /** * 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직 * - * @param targetUsers 라벨러 타겟 목록 - * @param targetInspectors 검수자 타겟 목록 + * @param targetUsers */ @Transactional - public void allocateAsc(List targetUsers, List targetInspectors) { + public void allocateAsc( + String autoType, + Integer stage, + List targetUsers, + List targetInspectors) + throws Exception { Long lastId = null; // geom 잔여건수 != 프론트에서 넘어 온 총 건수 -> return Long chargeCnt = labelAllocateCoreService.findLabelUnAssignedCnt(3L); // TODO - Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); - if (!Objects.equals(chargeCnt, totalDemand)) { - log.info("chargeCnt != totalDemand"); + // Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); + // if (!Objects.equals(chargeCnt, totalDemand)) { + // log.info("chargeCnt != totalDemand"); + // return; + // } + + if (chargeCnt <= 0) { return; } - // 라벨러에게 건수만큼 할당 + List allIds = labelAllocateCoreService.fetchNextIds(lastId, chargeCnt); + int index = 0; for (TargetUser target : targetUsers) { - int remaining = target.getDemand(); + int end = index + target.getDemand(); + List sub = allIds.subList(index, end); - while (remaining > 0) { - - int batchSize = Math.min(remaining, 100); - List ids = labelAllocateCoreService.fetchNextIds(lastId, batchSize); - - if (ids.isEmpty()) { - return; // 더이상 할당할 데이터가 없으면 return - } - - labelAllocateCoreService.assignOwner(ids, target.getUserId()); - - remaining -= ids.size(); - lastId = ids.get(ids.size() - 1); - } + labelAllocateCoreService.assignOwner(sub, target.getUserId()); + index = end; } // 검수자에게 userCount명 만큼 할당 List list = labelAllocateCoreService.findAssignedLabelerList(3L); - int reviewerIndex = 0; - int count = 0; - log.info("list : " + list.size()); + int from = 0; - for (LabelAllocateDto.Basic labeler : list) { - TargetInspector inspector = targetInspectors.get(reviewerIndex); - labelAllocateCoreService.assignInspector( - labeler.getAssignmentUid(), inspector.getInspectorUid()); - count++; + for (TargetInspector inspector : targetInspectors) { + int to = Math.min(from + inspector.getUserCount(), list.size()); - if (count == inspector.getUserCount()) { - reviewerIndex++; - count = 0; + if (from >= to) { + break; } + + List assignmentUids = + list.subList(from, to).stream().map(LabelAllocateDto.Basic::getAssignmentUid).toList(); + + labelAllocateCoreService.assignInspectorBulk(assignmentUids, inspector.getInspectorUid()); + + from = to; } } @@ -145,4 +145,8 @@ public class LabelAllocateService { return WorkerListResponse.builder().progressInfo(progressInfo).workers(workers).build(); } + + public InferenceDetail findInferenceDetail(Long analUid) { + return labelAllocateCoreService.findInferenceDetail(analUid); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java index c1719913..e7b53b73 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java @@ -1,6 +1,7 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; @@ -18,7 +19,7 @@ public class LabelAllocateCoreService { private final LabelAllocateRepository labelAllocateRepository; - public List fetchNextIds(Long lastId, int batchSize) { + public List fetchNextIds(Long lastId, Long batchSize) { return labelAllocateRepository.fetchNextIds(lastId, batchSize); } @@ -62,4 +63,12 @@ public class LabelAllocateCoreService { String workerId, String workerType, LocalDate date, Long analUid) { return labelAllocateRepository.findDailyProcessedCount(workerId, workerType, date, analUid); } + + public void assignInspectorBulk(List assignmentUids, String inspectorUid) { + labelAllocateRepository.assignInspectorBulk(assignmentUids, inspectorUid); + } + + public InferenceDetail findInferenceDetail(Long analUid) { + return labelAllocateRepository.findInferenceDetail(analUid); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalEntity.java index b2aeaf6d..dc9b1340 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalEntity.java @@ -103,4 +103,7 @@ public class MapSheetAnalEntity { @ColumnDefault("now()") @Column(name = "updated_dttm") private ZonedDateTime updatedDttm; + + @Column(name = "gukyuin_apply_dttm") + private ZonedDateTime gukyuinApplyDttm; } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java index 5392d88f..df73428b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.label; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; @@ -10,7 +11,7 @@ import java.util.UUID; public interface LabelAllocateRepositoryCustom { - List fetchNextIds(Long lastId, int batchSize); + List fetchNextIds(Long lastId, Long batchSize); void assignOwner(List ids, String userId); @@ -31,4 +32,8 @@ public interface LabelAllocateRepositoryCustom { // 작업자별 일일 처리량 조회 Long findDailyProcessedCount(String workerId, String workerType, LocalDate date, Long analUid); + + void assignInspectorBulk(List assignmentUids, String inspectorUid); + + InferenceDetail findInferenceDetail(Long analUid); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index 7ea657dc..88d07305 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -6,6 +6,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapShee import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo; @@ -15,6 +16,7 @@ import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -42,7 +44,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @PersistenceContext private EntityManager em; @Override - public List fetchNextIds(Long lastId, int batchSize) { + public List fetchNextIds(Long lastId, Long batchSize) { return queryFactory .select(mapSheetAnalDataInferenceGeomEntity.geoUid) @@ -53,7 +55,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(2022), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(2024), mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.asc()) + .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) .limit(batchSize) .fetch(); } @@ -65,28 +67,28 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto queryFactory .update(mapSheetAnalDataInferenceGeomEntity) .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) + .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) .execute(); // 라벨러 할당 테이블에 insert + String sql = + """ + insert into tb_labeling_assignment + (assignment_uid, inference_geom_uid, worker_uid, + work_state, assign_group_id, anal_uid) + values (?, ?, ?, ?, ?, ?) + """; + for (Long geoUid : ids) { - queryFactory - .insert(labelingAssignmentEntity) - .columns( - labelingAssignmentEntity.assignmentUid, - labelingAssignmentEntity.inferenceGeomUid, - labelingAssignmentEntity.workerUid, - labelingAssignmentEntity.workState, - labelingAssignmentEntity.assignGroupId, - labelingAssignmentEntity.analUid) - .values( - UUID.randomUUID(), - geoUid, - userId, - LabelState.ASSIGNED.getId(), - "", // TODO: 도엽번호 - 3) - .execute(); + em.createNativeQuery(sql) + .setParameter(1, UUID.randomUUID()) + .setParameter(2, geoUid) + .setParameter(3, userId) + .setParameter(4, LabelState.ASSIGNED.getId()) + .setParameter(5, "") + .setParameter(6, 3) + .executeUpdate(); } em.flush(); @@ -379,4 +381,38 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto return count != null ? count : 0L; } + + @Override + public void assignInspectorBulk(List assignmentUids, String inspectorUid) { + queryFactory + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.inspectorUid, inspectorUid) + .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) + .execute(); + + em.clear(); + } + + @Override + public InferenceDetail findInferenceDetail(Long analUid) { + return queryFactory + .select( + Projections.constructor( + InferenceDetail.class, + mapSheetAnalEntity.analTitle, + Expressions.numberTemplate(Integer.class, "{0}", 4), + mapSheetAnalEntity.gukyuinApplyDttm, + mapSheetAnalEntity.detectingCnt, + labelingAssignmentEntity.workerUid.countDistinct(), + labelingAssignmentEntity.inspectorUid.countDistinct())) + .from(mapSheetAnalEntity) + .innerJoin(labelingAssignmentEntity) + .on(mapSheetAnalEntity.id.eq(labelingAssignmentEntity.analUid)) + .where(mapSheetAnalEntity.id.eq(analUid)) + .groupBy( + mapSheetAnalEntity.analTitle, + mapSheetAnalEntity.gukyuinApplyDttm, + mapSheetAnalEntity.detectingCnt) + .fetchOne(); + } }