From 525120f65104bfb0a04f6b7cc4fb9345c4d3734d Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Fri, 20 Mar 2026 22:42:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=B8=8A=E4=BC=A0=E5=B0=B1?= =?UTF-8?q?=E8=81=9A=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KnowledgePointApplicationServiceImpl.java | 1 - .../domain/dto/KnowledgePointDTO.java | 3 ++ .../domain/entity/KnowledgePointEntity.java | 10 ++++- .../service/KnowledgeClusterBaseService.java | 8 ++++ .../impl/KnowledgeClusterBaseServiceImpl.java | 11 ++++++ .../UploadInformationDomainServiceImpl.java | 24 ++++++++++++ .../AlgorithmApplicationService.java | 6 +++ .../impl/AlgorithmApplicationServiceImpl.java | 9 +++++ .../controller/InteractionController.java | 11 +++--- .../PostToClusteringDomainService.java | 3 ++ .../service/SaveClusterDomainService.java | 4 ++ .../PostToClusteringDomainServiceImpl.java | 39 +++++++++++++++++++ .../impl/SaveClusterDomainServiceImpl.java | 37 ++++++++++++++++++ .../impl/InitTaskDomainServiceImpl.java | 18 ++++++++- 14 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/project/information/domain/service/KnowledgeClusterBaseService.java create mode 100644 src/main/java/com/project/information/domain/service/impl/KnowledgeClusterBaseServiceImpl.java diff --git a/src/main/java/com/project/information/application/impl/KnowledgePointApplicationServiceImpl.java b/src/main/java/com/project/information/application/impl/KnowledgePointApplicationServiceImpl.java index c588eb0..2f60c9b 100644 --- a/src/main/java/com/project/information/application/impl/KnowledgePointApplicationServiceImpl.java +++ b/src/main/java/com/project/information/application/impl/KnowledgePointApplicationServiceImpl.java @@ -79,7 +79,6 @@ public class KnowledgePointApplicationServiceImpl implements KnowledgePointAppli } // 成功后更新状态 updateStatusInformation(null, InformationParseStatusEnum.InProgress.getValue(), id); - // 聚类 } catch (Exception e) { log.error("解析异常, ID:{}", id, e); diff --git a/src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java b/src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java index 400e67c..fb822b7 100644 --- a/src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java +++ b/src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java @@ -24,6 +24,9 @@ public class KnowledgePointDTO extends BaseDTO { private List examFocusDTOList; + private Long clusterId; + + @Data public static class ExamFocusDTO { /*考点底色*/ diff --git a/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java b/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java index 0a33bb7..2392279 100644 --- a/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java +++ b/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java @@ -24,7 +24,9 @@ import java.util.function.Supplier; @Data @Table(name = "evaluator_knowledge_point" , - indexes = {@Index(name = "Idx_informationId", columnList = "information_id")}) + indexes = {@Index(name = "Idx_informationId", columnList = "information_id") , + @Index(name = "Idx_clusterId", columnList = "cluster_id") , + }) @Entity @TableName(value = "evaluator_knowledge_point") @EqualsAndHashCode(callSuper = true) @@ -56,6 +58,12 @@ public class KnowledgePointEntity extends BaseEntity { @Column(name = "exam_focus_list", columnDefinition = "json comment '考点集合'") private List examFocusList; + + @Column(name = "cluster_id") + @TableField("cluster_id") + @Comment("所属知识点簇ID") + private Long clusterId; + @Data public static class ExamFocus { /*考点底色*/ diff --git a/src/main/java/com/project/information/domain/service/KnowledgeClusterBaseService.java b/src/main/java/com/project/information/domain/service/KnowledgeClusterBaseService.java new file mode 100644 index 0000000..ac14717 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/KnowledgeClusterBaseService.java @@ -0,0 +1,8 @@ +package com.project.information.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.information.domain.entity.KnowledgeClusterEntity; +import com.project.information.domain.entity.KnowledgePointEntity; + +public interface KnowledgeClusterBaseService extends IService { +} diff --git a/src/main/java/com/project/information/domain/service/impl/KnowledgeClusterBaseServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/KnowledgeClusterBaseServiceImpl.java new file mode 100644 index 0000000..673f5e9 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/KnowledgeClusterBaseServiceImpl.java @@ -0,0 +1,11 @@ +package com.project.information.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.information.domain.entity.KnowledgeClusterEntity; +import com.project.information.domain.service.KnowledgeClusterBaseService; +import com.project.information.mapper.KnowledgeClusterMapper; +import org.springframework.stereotype.Service; + +@Service +public class KnowledgeClusterBaseServiceImpl extends ServiceImpl implements KnowledgeClusterBaseService { +} diff --git a/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java index b5c39e7..75ba246 100644 --- a/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java +++ b/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java @@ -11,19 +11,24 @@ import com.project.base.domain.exception.BusinessErrorException; import com.project.base.domain.result.Result; import com.project.information.application.KnowledgePointApplicationService; import com.project.information.domain.dto.InformationDTO; +import com.project.information.domain.dto.KnowledgePointDTO; import com.project.information.domain.entity.InformationEntity; +import com.project.information.domain.entity.KnowledgePointEntity; import com.project.information.domain.entity.ProductLineEntity; import com.project.information.domain.enums.InformationParseStatusEnum; import com.project.information.domain.param.FileCheckItem; import com.project.information.domain.service.InformationBaseService; +import com.project.information.domain.service.KnowledgePointBaseService; import com.project.information.domain.service.ProductLineBaseService; import com.project.information.domain.service.UploadInformationDomainService; import com.project.information.utils.MinIoUtils; +import com.project.interaction.application.AlgorithmApplicationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import java.io.InputStream; import java.util.*; @@ -38,9 +43,15 @@ public class UploadInformationDomainServiceImpl implements UploadInformationDoma private MinIoUtils minIoUtils; @Autowired private KnowledgePointApplicationService knowledgePointApplicationService; + + @Autowired + private KnowledgePointBaseService knowledgePointBaseService; @Autowired private CustomIdGenerator customIdGenerator; + @Autowired + private AlgorithmApplicationService algorithmApplicationService; + private static final long MAX_SIZE = 50 * 1024 * 1024; // 50MB 限制 @Override @@ -135,6 +146,19 @@ public class UploadInformationDomainServiceImpl implements UploadInformationDoma //发起解析文档知识点 knowledgePointApplicationService.parse(fileMap); + // 聚类 + for (Map.Entry entry : fileMap.entrySet()) { + Long informationId = entry.getKey(); + List list = knowledgePointBaseService.lambdaQuery() + .eq(KnowledgePointEntity::getInformationId, informationId).list().stream() + .map(entity -> entity.toDTO(KnowledgePointDTO::new)).toList(); + if (CollUtil.isNotEmpty(list)) { + algorithmApplicationService.postToClusteringByInformationId(informationId , list); + } + InformationEntity byId = informationBaseService.getById(informationId); + byId.setParseStatus(InformationParseStatusEnum.Success.getValue()); + informationBaseService.updateById(byId); + } return Result.success(String.format("上传成功:【%s】" , String.join("," , successFiles))); } diff --git a/src/main/java/com/project/interaction/application/AlgorithmApplicationService.java b/src/main/java/com/project/interaction/application/AlgorithmApplicationService.java index 13c60bc..2037fb0 100644 --- a/src/main/java/com/project/interaction/application/AlgorithmApplicationService.java +++ b/src/main/java/com/project/interaction/application/AlgorithmApplicationService.java @@ -20,9 +20,15 @@ public interface AlgorithmApplicationService { void postToClustering(Long taskId, List kpList); + void postToClusteringByInformationId(Long informationId, List kpList); + void postToGenerateQuestion(List dtoList , QuestionTypeEnum questionType , int num) throws Exception; void saveCluster(Long taskId, List clusters) throws Exception; + + void saveClusterByInformationId(Long informationId, List clusters) throws Exception; + + Result saveQuestion(QuestionDTO dto) throws Exception; } diff --git a/src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java b/src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java index 6e1088f..38a2f1b 100644 --- a/src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java +++ b/src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java @@ -34,6 +34,10 @@ public class AlgorithmApplicationServiceImpl implements AlgorithmApplicationServ postToClusteringDomainService.postToClustering(taskId , kpList); } + @Override + public void postToClusteringByInformationId(Long informationId, List kpList) { + + } @Override public void postToGenerateQuestion(List dtoList, QuestionTypeEnum questionType, int num) throws Exception { @@ -46,6 +50,11 @@ public class AlgorithmApplicationServiceImpl implements AlgorithmApplicationServ saveClusterDomainService.saveCluster(taskId , clusters); } + @Override + public void saveClusterByInformationId(Long informationId, List clusters) throws Exception { + saveClusterDomainService.saveClusterByInformationId(informationId , clusters); + } + @Override public Result saveQuestion(QuestionDTO dto) throws Exception { return saveQuestionDomainService.save(dto); diff --git a/src/main/java/com/project/interaction/controller/InteractionController.java b/src/main/java/com/project/interaction/controller/InteractionController.java index eb79810..3094af9 100644 --- a/src/main/java/com/project/interaction/controller/InteractionController.java +++ b/src/main/java/com/project/interaction/controller/InteractionController.java @@ -17,14 +17,15 @@ public class InteractionController { private AlgorithmApplicationService algorithmApplicationService; +// @PostMapping("/saveCluster") +// public Result saveCluster(ClusterCallbackDTO dto) throws Exception{ +// algorithmApplicationService.saveCluster(dto.getTaskId(), dto.getClusters()); +// return Result.success("保存成功"); +// } - /** - * 手动触发同步接口 - * 强刷:/sync/all?force=true - */ @PostMapping("/saveCluster") public Result saveCluster(ClusterCallbackDTO dto) throws Exception{ - algorithmApplicationService.saveCluster(dto.getTaskId(), dto.getClusters()); + algorithmApplicationService.saveClusterByInformationId(dto.getTaskId(), dto.getClusters()); return Result.success("保存成功"); } diff --git a/src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java b/src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java index f9621eb..795f437 100644 --- a/src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java +++ b/src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java @@ -6,4 +6,7 @@ import java.util.List; public interface PostToClusteringDomainService { void postToClustering(Long taskId, List kpList); + + void postToClusteringByInformationId(Long informationId, List kpList); + } diff --git a/src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java b/src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java index 57e3bcd..16aa454 100644 --- a/src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java +++ b/src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java @@ -6,4 +6,8 @@ import java.util.List; public interface SaveClusterDomainService { void saveCluster(Long taskId, List clusters) throws Exception; + + + void saveClusterByInformationId(Long informationId, List clusters) throws Exception; + } diff --git a/src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java index b8bbc6f..a42473f 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java @@ -65,4 +65,43 @@ public class PostToClusteringDomainServiceImpl implements PostToClusteringDomain log.error(">>> [Interactor] 算法端通信异常", e); } } + + @Override + public void postToClusteringByInformationId(Long informationId, List kpList) { + // 构建请求 DTO (AlgoRequestDTO) + Map requestBody = Collections.singletonMap("tasks", + Collections.singletonList(new ClusterQueryDTO(informationId, kpList))); + try { + log.info(">>> [Interactor] 正在向算法端发送请求, informationId: {}", informationId); + algorithmWebClient.post() + .uri(clusterUrl) + .bodyValue(requestBody) + .retrieve() + .bodyToMono(String.class) + .flatMap(jsonStr -> Mono.fromCallable(() -> { + ObjectMapper mapper = new ObjectMapper(); + // 第一次 readValue:去掉外层引号和转义符,把字符串变成正常的 JSON 格式 + // 此时 unescapedJson 的值会变成 {"code": 200, "message": "请求成功!"} + String unescapedJson = mapper.readValue(jsonStr, String.class); + + // 第二次 readValue:将标准的 JSON 字符串解析为 DTO + return mapper.readValue(unescapedJson, ClusterResultDTO.class); + })) + .doOnError(error -> log.error(">>> [Interactor] 算法端推送异常, informationId: {}, 原因: {}", + informationId, error.getMessage())) + // 结果处理(非阻塞订阅) + .subscribe( + result -> { + log.info(">>> [Interactor] 算法端已成功接收任务: {}", informationId); + }, + error -> { + // 这里处理订阅过程中的报错,防止异常被丢弃 + log.error(">>> [Interactor] 任务 {} 订阅执行失败", informationId, error); + } + ); + + } catch (Exception e) { + log.error(">>> [Interactor] 算法端通信异常", e); + } + } } diff --git a/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java index ea76da7..484153c 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java @@ -1,8 +1,11 @@ package com.project.interaction.domain.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.project.information.domain.dto.KnowledgePointDTO; +import com.project.information.domain.entity.KnowledgeClusterEntity; import com.project.information.domain.entity.KnowledgePointEntity; +import com.project.information.domain.service.KnowledgeClusterBaseService; import com.project.information.domain.service.KnowledgePointBaseService; import com.project.interaction.domain.dto.ClusterCallbackDTO; import com.project.interaction.domain.dto.ProduceDTO; @@ -21,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; +import java.util.stream.Collectors; @Service @Slf4j @@ -34,6 +38,9 @@ public class SaveClusterDomainServiceImpl implements SaveClusterDomainService { @Autowired private TaskKnowledgePointBaseService taskKnowledgePointBaseService; + @Autowired + private KnowledgeClusterBaseService knowledgeClusterBaseService; + @Autowired private KnowledgePointBaseService knowledgePointBaseService; @@ -43,6 +50,36 @@ public class SaveClusterDomainServiceImpl implements SaveClusterDomainService { private final Integer ROUND_NUM = 2; + + @Override + public void saveClusterByInformationId(Long informationId, List clusters) throws Exception { + // 原来有要删掉 + List list = knowledgeClusterBaseService.lambdaQuery().eq(KnowledgeClusterEntity::getInformationId, informationId).list(); + if (CollUtil.isNotEmpty(list)) { + knowledgeClusterBaseService.removeByIds(list.stream().map(KnowledgeClusterEntity::getId) + .collect(Collectors.toList())); + } + + + for (ClusterCallbackDTO.ClusterItem cluster : clusters) { + // 1.保存知识点簇 + KnowledgeClusterEntity clusterEntity = new KnowledgeClusterEntity(); + clusterEntity.setInformationId(informationId); + clusterEntity.setClusterTopic(cluster.getTopic()); + clusterEntity.setClusterSize(cluster.getAtomIdList().size()); + knowledgeClusterBaseService.save(clusterEntity); + + + // 2.提取该簇下的原子知识点,并保存任务知识点 + List kpList = knowledgePointBaseService.list(new LambdaQueryWrapper() + .in(KnowledgePointEntity::getId, cluster.getAtomIdList())); + + kpList.forEach(knowledgePointEntity -> knowledgePointEntity.setClusterId(clusterEntity.getId())); + // 批量插入 + knowledgePointBaseService.updateBatchById(kpList); + } + } + @Override public void saveCluster(Long taskId, List clusters) { TaskEntity taskEntity = taskBaseService.getById(taskId); diff --git a/src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java index c4077c0..bd73778 100644 --- a/src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java +++ b/src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java @@ -3,19 +3,23 @@ package com.project.task.domain.service.impl; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.project.information.domain.dto.KnowledgePointDTO; +import com.project.information.domain.dto.ProductLineDTO; import com.project.information.domain.entity.InformationEntity; import com.project.information.domain.entity.KnowledgePointEntity; import com.project.information.domain.enums.InformationParseStatusEnum; import com.project.information.domain.service.InformationBaseService; import com.project.information.domain.service.KnowledgePointBaseService; import com.project.interaction.application.AlgorithmApplicationService; +import com.project.interaction.domain.dto.ClusterCallbackDTO; import com.project.task.domain.service.InitTaskDomainService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.stream.Collectors; @@ -48,7 +52,7 @@ public class InitTaskDomainServiceImpl implements InitTaskDomainService { }, taskInternalExecutor); } - public void handle(Long taskId, List docIds) { + public void handle(Long taskId, List docIds) throws Exception { boolean isReady = pollUntilDocsParsed(taskId, docIds); if (!isReady) { @@ -66,7 +70,17 @@ public class InitTaskDomainServiceImpl implements InitTaskDomainService { return; } if (CollUtil.isNotEmpty(kpList)) { - algorithmApplicationService.postToClustering(taskId , kpList); +// algorithmApplicationService.postToClustering(taskId , kpList); + // 组装成任务知识点 + Map> collect = kpList.stream().collect(Collectors.groupingBy(KnowledgePointDTO::getClusterId)); + List clusters = Lists.newArrayList(); + collect.forEach((key, value) -> { + ClusterCallbackDTO.ClusterItem clusterItem = new ClusterCallbackDTO.ClusterItem(); + clusterItem.setTopic(value.stream().map(KnowledgePointDTO::getId).map(String::valueOf).collect(Collectors.joining(","))); + clusterItem.setAtomIdList(value.stream().map(KnowledgePointDTO::getId).collect(Collectors.toList())); + clusters.add(clusterItem); + }); + algorithmApplicationService.saveCluster(taskId , clusters); log.info(">>> [任务初始化] 任务[{}]知识点已成功送往算法端,当前异步线程任务结束", taskId); } else { log.info(">>> [任务初始化] 任务[{}]知识点集合为空", taskId);