Browse Source

考试任务调用知识点簇聚类

master
luoweijian 1 month ago
parent
commit
f64ffadb33
  1. 3
      src/main/java/com/project/ding/config/SecurityConfig.java
  2. 7
      src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java
  3. 3
      src/main/java/com/project/information/domain/param/CheckDuplicatesParam.java
  4. 24
      src/main/java/com/project/interaction/application/AlgorithmApplicationService.java
  5. 47
      src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java
  6. 4
      src/main/java/com/project/interaction/config/WebClientConfig.java
  7. 29
      src/main/java/com/project/interaction/controller/InteractionController.java
  8. 40
      src/main/java/com/project/interaction/domain/dto/ClusterCallbackDTO.java
  9. 2
      src/main/java/com/project/interaction/domain/dto/ClusterQueryDTO.java
  10. 2
      src/main/java/com/project/interaction/domain/dto/ClusterResultDTO.java
  11. 2
      src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java
  12. 9
      src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java
  13. 8
      src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java
  14. 90
      src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java
  15. 10
      src/main/java/com/project/interactor/application/AlgorithmApplicationService.java
  16. 19
      src/main/java/com/project/interactor/application/impl/AlgorithmApplicationServiceImpl.java
  17. 4
      src/main/java/com/project/question/application/QuestionApplicationService.java
  18. 4
      src/main/java/com/project/question/application/TaskKnowledgeClusterApplicationService.java
  19. 8
      src/main/java/com/project/question/application/impl/QuestionApplicationServiceImpl.java
  20. 8
      src/main/java/com/project/question/application/impl/TaskKnowledgeClusterApplicationServiceImpl.java
  21. 29
      src/main/java/com/project/question/config/QuestionAsyncThreadPoolConfig.java
  22. 9
      src/main/java/com/project/question/domain/dto/QuestionDTO.java
  23. 10
      src/main/java/com/project/question/domain/dto/TaskKnowledgePointDTO.java
  24. 3
      src/main/java/com/project/question/domain/entity/QuestionEntity.java
  25. 50
      src/main/java/com/project/question/domain/entity/QuestionKpRelEntity.java
  26. 2
      src/main/java/com/project/question/domain/entity/TaskKnowledgeClusterEntity.java
  27. 2
      src/main/java/com/project/question/domain/entity/TaskKnowledgePointEntity.java
  28. 2
      src/main/java/com/project/question/domain/enums/QuestionUseStatusEnum.java
  29. 9
      src/main/java/com/project/question/domain/service/GenerateQuestionDomainService.java
  30. 10
      src/main/java/com/project/question/domain/service/SamplingStrategy.java
  31. 7
      src/main/java/com/project/question/domain/service/TaskKnowledgeClusterBaseService.java
  32. 7
      src/main/java/com/project/question/domain/service/TaskKnowledgePointBaseService.java
  33. 61
      src/main/java/com/project/question/domain/service/impl/GenerateQuestionDomainServiceImpl.java
  34. 39
      src/main/java/com/project/question/domain/service/impl/RandomSamplingStrategy.java
  35. 12
      src/main/java/com/project/question/domain/service/impl/TaskKnowledgeClusterBaseServiceImpl.java
  36. 12
      src/main/java/com/project/question/domain/service/impl/TaskKnowledgePointBaseServiceImpl.java
  37. 4
      src/main/java/com/project/question/mapper/TaskKnowledgeClusterMapper.java
  38. 4
      src/main/java/com/project/question/mapper/TaskKnowledgePointMapper.java
  39. 19
      src/main/java/com/project/task/config/TaskAsyncThreadPoolConfig.java
  40. 2
      src/main/java/com/project/task/domain/entity/ExamRecordEntity.java
  41. 2
      src/main/java/com/project/task/domain/entity/TaskUserEntity.java
  42. 2
      src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java

3
src/main/java/com/project/ding/config/SecurityConfig.java

@ -28,7 +28,8 @@ public class SecurityConfig {
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
// 登录放行
.requestMatchers("/api/login/**").permitAll()
.requestMatchers("/api/login/**" ,
"/api/interaction/**").permitAll()
// 管理端锁定
.requestMatchers("/api/admin/**").hasRole("ADMIN")
// 其余(考生端)需登录

7
src/main/java/com/project/information/domain/dto/KnowledgePointDTO.java

@ -1,7 +1,12 @@
package com.project.information.domain.dto;
import com.project.base.domain.dto.BaseDTO;
import lombok.Data;
@Data
public class KnowledgePointDTO {
public class KnowledgePointDTO extends BaseDTO {
private Long id;
private String content;
}

3
src/main/java/com/project/information/domain/param/CheckDuplicatesParam.java

@ -29,4 +29,5 @@ public class CheckDuplicatesParam {
// 处理解析异常
throw new BusinessErrorException("Json解析失败");
}
}}
}
}

24
src/main/java/com/project/interaction/application/AlgorithmApplicationService.java

@ -0,0 +1,24 @@
package com.project.interaction.application;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.interaction.domain.dto.ClusterCallbackDTO;
import com.project.question.domain.dto.TaskKnowledgePointDTO;
import com.project.task.domain.enums.QuestionTypeEnum;
import java.util.List;
public interface AlgorithmApplicationService {
/**
* 知识点分簇
* @param taskId
* @param kpList
*/
void postToClustering(Long taskId, List<KnowledgePointDTO> kpList);
void generateQuestion(List<TaskKnowledgePointDTO> dtoList , QuestionTypeEnum questionType , int num);
void saveCluster(Long taskId, List<ClusterCallbackDTO.ClusterItem> clusters) throws Exception;
}

47
src/main/java/com/project/interaction/application/impl/AlgorithmApplicationServiceImpl.java

@ -0,0 +1,47 @@
package com.project.interaction.application.impl;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.interaction.application.AlgorithmApplicationService;
import com.project.interaction.domain.dto.ClusterCallbackDTO;
import com.project.interaction.domain.service.PostToClusteringDomainService;
import com.project.interaction.domain.service.SaveClusterDomainService;
import com.project.question.domain.dto.TaskKnowledgePointDTO;
import com.project.question.domain.enums.QuestionSourceTypeEnum;
import com.project.task.domain.enums.QuestionTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AlgorithmApplicationServiceImpl implements AlgorithmApplicationService {
@Autowired
private PostToClusteringDomainService postToClusteringDomainService;
@Autowired
private SaveClusterDomainService saveClusterDomainService;
@Override
public void postToClustering(Long taskId, List<KnowledgePointDTO> kpList) {
postToClusteringDomainService.postToClustering(taskId , kpList);
}
@Override
public void generateQuestion(List<TaskKnowledgePointDTO> dtoList, QuestionTypeEnum questionType, int num) {
System.out.println(String.format("<=======生成了%d道%s, 结合了知识点【%s】属于%s=======>" ,
num ,
questionType.getDescription() ,
String.join("," , dtoList.stream().map(dto -> dto.getId().toString()).toList()) ,
dtoList.size() > 1 ? QuestionSourceTypeEnum.Multi_Concept.getDesc() : QuestionSourceTypeEnum.Single_Concept.getDesc()));
}
@Override
public void saveCluster(Long taskId, List<ClusterCallbackDTO.ClusterItem> clusters) throws Exception {
try {
saveClusterDomainService.saveCluster(taskId , clusters);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

4
src/main/java/com/project/interactor/config/WebClientConfig.java → src/main/java/com/project/interaction/config/WebClientConfig.java

@ -1,4 +1,4 @@
package com.project.interactor.config;
package com.project.interaction.config;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit;
@Configuration
public class WebClientConfig {
@Value("${algo.baseUrl}")
@Value("${algo.baseUrl:''}")
private String baseUrl;
@Bean(name = "algorithmWebClient")

29
src/main/java/com/project/interaction/controller/InteractionController.java

@ -0,0 +1,29 @@
package com.project.interaction.controller;
import com.project.base.domain.result.Result;
import com.project.interaction.application.AlgorithmApplicationService;
import com.project.interaction.domain.dto.ClusterCallbackDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/interaction")
public class InteractionController {
@Autowired
private AlgorithmApplicationService algorithmApplicationService;
/**
* 手动触发同步接口
* 强刷/sync/all?force=true
*/
@PostMapping("/saveCluster")
public Result<String> saveCluster(ClusterCallbackDTO dto) throws Exception{
algorithmApplicationService.saveCluster(dto.getTaskId(), dto.getClusters());
return Result.success("保存成功");
}
}

40
src/main/java/com/project/interaction/domain/dto/ClusterCallbackDTO.java

@ -0,0 +1,40 @@
package com.project.interaction.domain.dto;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.base.domain.exception.BusinessErrorException;
import com.project.information.domain.param.FileCheckItem;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.List;
@Data
public class ClusterCallbackDTO {
private Long taskId;
private String clusters;
@Data
public static class ClusterItem {
private String topic;
private List<Long> atomIdList;
}
// 手动解析为List的方法
public List<ClusterItem> getClusters() {
if (StringUtils.isEmpty(clusters)) {
return Collections.emptyList();
}
try {
return new ObjectMapper().readValue(
clusters,
new TypeReference<List<ClusterItem>>() {});
} catch (JsonProcessingException e) {
// 处理解析异常
throw new BusinessErrorException("Json解析失败");
}
}
}

2
src/main/java/com/project/interactor/domain/dto/ClusterQueryDTO.java → src/main/java/com/project/interaction/domain/dto/ClusterQueryDTO.java

@ -1,4 +1,4 @@
package com.project.interactor.domain.dto;
package com.project.interaction.domain.dto;
import com.project.information.domain.dto.KnowledgePointDTO;

2
src/main/java/com/project/interactor/domain/dto/ClusterResultDTO.java → src/main/java/com/project/interaction/domain/dto/ClusterResultDTO.java

@ -1,4 +1,4 @@
package com.project.interactor.domain.dto;
package com.project.interaction.domain.dto;
import lombok.Data;

2
src/main/java/com/project/interactor/domain/service/PostToClusteringDomainService.java → src/main/java/com/project/interaction/domain/service/PostToClusteringDomainService.java

@ -1,4 +1,4 @@
package com.project.interactor.domain.service;
package com.project.interaction.domain.service;
import com.project.information.domain.dto.KnowledgePointDTO;

9
src/main/java/com/project/interaction/domain/service/SaveClusterDomainService.java

@ -0,0 +1,9 @@
package com.project.interaction.domain.service;
import com.project.interaction.domain.dto.ClusterCallbackDTO;
import java.util.List;
public interface SaveClusterDomainService {
void saveCluster(Long taskId, List<ClusterCallbackDTO.ClusterItem> clusters) throws Exception;
}

8
src/main/java/com/project/interactor/domain/service/impl/PostToClusteringDomainServiceImpl.java → src/main/java/com/project/interaction/domain/service/impl/PostToClusteringDomainServiceImpl.java

@ -1,9 +1,9 @@
package com.project.interactor.domain.service.impl;
package com.project.interaction.domain.service.impl;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.interactor.domain.dto.ClusterQueryDTO;
import com.project.interactor.domain.dto.ClusterResultDTO;
import com.project.interactor.domain.service.PostToClusteringDomainService;
import com.project.interaction.domain.dto.ClusterQueryDTO;
import com.project.interaction.domain.dto.ClusterResultDTO;
import com.project.interaction.domain.service.PostToClusteringDomainService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;

90
src/main/java/com/project/interaction/domain/service/impl/SaveClusterDomainServiceImpl.java

@ -0,0 +1,90 @@
package com.project.interaction.domain.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.information.domain.entity.KnowledgePointEntity;
import com.project.information.domain.service.KnowledgePointBaseService;
import com.project.interaction.domain.dto.ClusterCallbackDTO;
import com.project.interaction.domain.service.SaveClusterDomainService;
import com.project.question.domain.entity.TaskKnowledgeClusterEntity;
import com.project.question.domain.entity.TaskKnowledgePointEntity;
import com.project.question.domain.enums.QuestionSourceTypeEnum;
import com.project.question.domain.service.GenerateQuestionDomainService;
import com.project.question.domain.service.TaskKnowledgeClusterBaseService;
import com.project.question.domain.service.TaskKnowledgePointBaseService;
import com.project.task.domain.entity.TaskEntity;
import com.project.task.domain.enums.QuestionTypeEnum;
import com.project.task.domain.service.TaskBaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
@Service
@Slf4j
public class SaveClusterDomainServiceImpl implements SaveClusterDomainService {
@Autowired
private TaskBaseService taskBaseService;
@Autowired
private TaskKnowledgeClusterBaseService taskKnowledgeClusterBaseService;
@Autowired
private TaskKnowledgePointBaseService taskKnowledgePointBaseService;
@Autowired
private KnowledgePointBaseService knowledgePointBaseService;
@Autowired
private GenerateQuestionDomainService generateQuestionDomainService;
@Override
public void saveCluster(Long taskId, List<ClusterCallbackDTO.ClusterItem> clusters) throws Exception {
TaskEntity taskEntity = taskBaseService.getById(taskId);
int u = 0;
if (Objects.isNull(taskEntity) || Objects.isNull(taskEntity.getParticipantNum()) || taskEntity.getParticipantNum() <= 0) {
return;
}
u = taskEntity.getParticipantNum();
log.info(">>> [回调处理] 开始持久化任务[{}]聚类结果,计划人数U={}", taskId, u);
for (ClusterCallbackDTO.ClusterItem cluster : clusters) {
// 1.保存任务知识点簇
TaskKnowledgeClusterEntity clusterEntity = new TaskKnowledgeClusterEntity();
clusterEntity.setTaskId(taskId);
clusterEntity.setClusterTopic(cluster.getTopic());
clusterEntity.setClusterSize(cluster.getAtomIdList().size());
taskKnowledgeClusterBaseService.save(clusterEntity);
// 2.提取该簇下的原子知识点,并保存任务知识点
List<KnowledgePointDTO> kpList = knowledgePointBaseService.list(new LambdaQueryWrapper<KnowledgePointEntity>()
.in(KnowledgePointEntity::getId, cluster.getAtomIdList()))
.stream().map(entity -> entity.toDTO(KnowledgePointDTO::new)).toList();
List<TaskKnowledgePointEntity> taskKpList = kpList.stream().map(atomKp -> {
TaskKnowledgePointEntity taskKp = new TaskKnowledgePointEntity();
taskKp.setTaskId(taskId);
taskKp.setClusterId(clusterEntity.getId());
taskKp.setAtomId(atomKp.getId());
taskKp.setContent(atomKp.getContent());
return taskKp;
}).toList();
// 批量插入
taskKnowledgePointBaseService.saveBatch(taskKpList);
// 生成目标量
int targetNum = (int) Math.ceil(1.2 * u);
for (TaskKnowledgePointEntity kp : taskKpList) {
// 调用题目生成方法
for (QuestionTypeEnum value : QuestionTypeEnum.values()) {
generateQuestionDomainService.produce(kp.getId(), value , QuestionSourceTypeEnum.Single_Concept , targetNum);
}
}
if (clusterEntity.getClusterSize() > 1) {
// 簇生成目标量
int clusterTargetNum = (int) Math.ceil(1.2 * u * clusterEntity.getClusterSize());
generateQuestionDomainService.produce(clusterEntity.getId(), QuestionTypeEnum.MULTIPLE_CHOICE ,QuestionSourceTypeEnum.Multi_Concept , clusterTargetNum);
}
}
}
}

10
src/main/java/com/project/interactor/application/AlgorithmApplicationService.java

@ -1,10 +0,0 @@
package com.project.interactor.application;
import com.project.information.domain.dto.KnowledgePointDTO;
import java.util.List;
public interface AlgorithmApplicationService {
void postToClustering(Long taskId, List<KnowledgePointDTO> kpList);
}

19
src/main/java/com/project/interactor/application/impl/AlgorithmApplicationServiceImpl.java

@ -1,19 +0,0 @@
package com.project.interactor.application.impl;
import com.project.information.domain.dto.KnowledgePointDTO;
import com.project.interactor.application.AlgorithmApplicationService;
import com.project.interactor.domain.service.PostToClusteringDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AlgorithmApplicationServiceImpl implements AlgorithmApplicationService {
@Autowired
private PostToClusteringDomainService postToClusteringDomainService;
@Override
public void postToClustering(Long taskId, List<KnowledgePointDTO> kpList) {
postToClusteringDomainService.postToClustering(taskId , kpList);
}
}

4
src/main/java/com/project/question/application/QuestionApplicationService.java

@ -0,0 +1,4 @@
package com.project.question.application;
public interface QuestionApplicationService {
}

4
src/main/java/com/project/question/application/TaskKnowledgeClusterApplicationService.java

@ -0,0 +1,4 @@
package com.project.question.application;
public interface TaskKnowledgeClusterApplicationService {
}

8
src/main/java/com/project/question/application/impl/QuestionApplicationServiceImpl.java

@ -0,0 +1,8 @@
package com.project.question.application.impl;
import com.project.question.application.QuestionApplicationService;
import org.springframework.stereotype.Service;
@Service
public class QuestionApplicationServiceImpl implements QuestionApplicationService {
}

8
src/main/java/com/project/question/application/impl/TaskKnowledgeClusterApplicationServiceImpl.java

@ -0,0 +1,8 @@
package com.project.question.application.impl;
import com.project.question.application.TaskKnowledgeClusterApplicationService;
import org.springframework.stereotype.Service;
@Service
public class TaskKnowledgeClusterApplicationServiceImpl implements TaskKnowledgeClusterApplicationService {
}

29
src/main/java/com/project/question/config/QuestionAsyncThreadPoolConfig.java

@ -0,0 +1,29 @@
package com.project.question.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class QuestionAsyncThreadPoolConfig {
/**
* 题目生成池 (高并发IO密集型)
* 核心允许并行处理不同的知识点
*/
@Bean(name = "questionGenExecutor")
public Executor questionGenExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 允许 5-10 个知识点同时进行 AI 出题
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("question-gen-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

9
src/main/java/com/project/question/domain/dto/QuestionDTO.java

@ -0,0 +1,9 @@
package com.project.question.domain.dto;
import com.project.base.domain.dto.BaseDTO;
import lombok.Data;
@Data
public class QuestionDTO extends BaseDTO {
private Long id;
}

10
src/main/java/com/project/question/domain/dto/TaskKnowledgePointDTO.java

@ -0,0 +1,10 @@
package com.project.question.domain.dto;
import com.project.base.domain.dto.BaseDTO;
import lombok.Data;
@Data
public class TaskKnowledgePointDTO extends BaseDTO {
private Long id;
}

3
src/main/java/com/project/question/domain/entity/QuestionEntity.java

@ -53,8 +53,9 @@ public class QuestionEntity extends BaseEntity {
@TableField("unique_hash")
private String uniqueHash;
@Column(name = "question_type", columnDefinition = "comment '题目类型'")
@Column(name = "question_type")
@TableField("question_type")
@Comment("题目类型")
private Integer questionType;
@TableField(value = "question_detail" , typeHandler = JacksonTypeHandler.class)

50
src/main/java/com/project/question/domain/entity/QuestionKpRelEntity.java

@ -0,0 +1,50 @@
package com.project.question.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
@Data
@Entity
@Table(name = "evaluator_question_kp_rel", indexes = {
@Index(name = "idx_kp_id", columnList = "kp_id"),
@Index(name = "idx_question_id", columnList = "question_id"),
@Index(name = "idx_task_id", columnList = "task_id")
})
@TableName("evaluator_question_kp_rel")
@EqualsAndHashCode(callSuper = true)
public class QuestionKpRelEntity extends BaseEntity {
@TableId(type = IdType.ASSIGN_ID)
@Id
private Long id;
@Column(name = "question_id")
@Comment("题目ID")
@TableField("question_id")
private Long questionId;
@Column(name = "kp_id")
@Comment("考试任务知识点ID")
private Long kpId;
@Column(name = "cluster_id")
@TableField("cluster_id")
@Comment("所属知识点簇ID")
private Long clusterId;
@Column(name = "task_id")
@Comment("所属考试任务ID (冗余字段,方便清理及统计)")
@TableField("task_id")
private Long taskId;
@Column(name = "question_type")
@TableField("question_type")
@Comment("题目类型")
private Integer questionType;
}

2
src/main/java/com/project/task/domain/entity/TaskKnowledgeClusterEntity.java → src/main/java/com/project/question/domain/entity/TaskKnowledgeClusterEntity.java

@ -1,4 +1,4 @@
package com.project.task.domain.entity;
package com.project.question.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;

2
src/main/java/com/project/task/domain/entity/TaskKnowledgePointEntity.java → src/main/java/com/project/question/domain/entity/TaskKnowledgePointEntity.java

@ -1,4 +1,4 @@
package com.project.task.domain.entity;
package com.project.question.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;

2
src/main/java/com/project/question/domain/enums/QuestionUseStatusEnum.java

@ -4,8 +4,8 @@ import com.project.base.domain.enums.HasValueEnum;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
@RequiredArgsConstructor
public enum QuestionUseStatusEnum implements HasValueEnum<Boolean> {
Not_Use(Boolean.FALSE) ,
Used(Boolean.TRUE);

9
src/main/java/com/project/question/domain/service/GenerateQuestionDomainService.java

@ -0,0 +1,9 @@
package com.project.question.domain.service;
import com.project.question.domain.enums.QuestionSourceTypeEnum;
import com.project.task.domain.enums.QuestionTypeEnum;
public interface GenerateQuestionDomainService {
void produce(Long sourceId, QuestionTypeEnum questionType , QuestionSourceTypeEnum sourceType, int needCount);
}

10
src/main/java/com/project/question/domain/service/SamplingStrategy.java

@ -0,0 +1,10 @@
package com.project.question.domain.service;
import com.project.question.domain.dto.TaskKnowledgePointDTO;
import java.util.List;
public interface SamplingStrategy {
List<TaskKnowledgePointDTO> sample(Long clusterId);
}

7
src/main/java/com/project/question/domain/service/TaskKnowledgeClusterBaseService.java

@ -0,0 +1,7 @@
package com.project.question.domain.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.question.domain.entity.TaskKnowledgeClusterEntity;
public interface TaskKnowledgeClusterBaseService extends IService<TaskKnowledgeClusterEntity> {
}

7
src/main/java/com/project/question/domain/service/TaskKnowledgePointBaseService.java

@ -0,0 +1,7 @@
package com.project.question.domain.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.question.domain.entity.TaskKnowledgePointEntity;
public interface TaskKnowledgePointBaseService extends IService<TaskKnowledgePointEntity> {
}

61
src/main/java/com/project/question/domain/service/impl/GenerateQuestionDomainServiceImpl.java

@ -0,0 +1,61 @@
package com.project.question.domain.service.impl;
import com.project.question.domain.dto.TaskKnowledgePointDTO;
import com.project.question.domain.enums.QuestionSourceTypeEnum;
import com.project.question.domain.service.GenerateQuestionDomainService;
import com.project.question.domain.service.SamplingStrategy;
import com.project.question.domain.service.TaskKnowledgePointBaseService;
import com.project.task.domain.enums.QuestionTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@Service
@Slf4j
public class GenerateQuestionDomainServiceImpl implements GenerateQuestionDomainService {
@Resource(name = "questionGenExecutor")
private Executor questionGenExecutor;
@Autowired
private TaskKnowledgePointBaseService taskKnowledgePointBaseService;
@Autowired
private SamplingStrategy samplingStrategy;
@Override
public void produce(Long sourceId, QuestionTypeEnum questionType , QuestionSourceTypeEnum sourceType, int needCount) {
if (needCount <= 0) {
return;
}
CompletableFuture.runAsync(() -> {
log.info(">>> [题库预生成] 准备生产任务: SourceID={}, Type={}, Count={}", sourceId, sourceType, needCount);
processBatch(sourceId,questionType , sourceType , needCount);
}, questionGenExecutor);
}
private void processBatch(Long sourceId, QuestionTypeEnum questionType , QuestionSourceTypeEnum sourceType, int count) {
// 如果是簇复合题,执行随机采样 2-4 个知识点
List<TaskKnowledgePointDTO> kpList;
if (QuestionSourceTypeEnum.Multi_Concept.equals(sourceType)) {
kpList = samplingStrategy.sample(sourceId); // 获取随机组合的 KPs
} else {
// 单 KP 逻辑:直接查出对应 KP 的内容
kpList = Collections.singletonList(taskKnowledgePointBaseService.getById(sourceId)
.toDTO(TaskKnowledgePointDTO::new));
}
// 2. 调用大模型并保存题目及其多对多关系 (QuestionPool & QuestionKpRel)
//
//aiLlmService.generateAndBatchSave(context, sourceType, count);
}
}

39
src/main/java/com/project/question/domain/service/impl/RandomSamplingStrategy.java

@ -0,0 +1,39 @@
package com.project.question.domain.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.project.question.domain.dto.TaskKnowledgePointDTO;
import com.project.question.domain.entity.TaskKnowledgePointEntity;
import com.project.question.domain.service.SamplingStrategy;
import com.project.question.domain.service.TaskKnowledgePointBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class RandomSamplingStrategy implements SamplingStrategy {
@Autowired
private TaskKnowledgePointBaseService taskKnowledgePointBaseService;
@Override
public List<TaskKnowledgePointDTO> sample(Long clusterId) {
List<TaskKnowledgePointDTO> dtoList = taskKnowledgePointBaseService.list(new LambdaQueryWrapper<TaskKnowledgePointEntity>()
.eq(TaskKnowledgePointEntity::getClusterId, clusterId))
.stream().map(entity -> entity.toDTO(TaskKnowledgePointDTO::new)).toList();
if (CollUtil.isEmpty(dtoList)) {
return Collections.emptyList();
}
// 确定采样数量:2 到 4 之间的随机数
int totalSize = dtoList.size();
int min = Math.min(totalSize, 2);
int max = Math.min(totalSize, 4);
int targetSampleSize = (min == max) ? min : RandomUtil.randomInt(min, max + 1);
Collections.shuffle(dtoList);
return dtoList.subList(0 , targetSampleSize);
}
}

12
src/main/java/com/project/question/domain/service/impl/TaskKnowledgeClusterBaseServiceImpl.java

@ -0,0 +1,12 @@
package com.project.question.domain.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.question.domain.entity.TaskKnowledgeClusterEntity;
import com.project.question.domain.service.TaskKnowledgeClusterBaseService;
import com.project.question.mapper.TaskKnowledgeClusterMapper;
import org.springframework.stereotype.Service;
@Service
public class TaskKnowledgeClusterBaseServiceImpl extends ServiceImpl<TaskKnowledgeClusterMapper, TaskKnowledgeClusterEntity> implements TaskKnowledgeClusterBaseService {
}

12
src/main/java/com/project/question/domain/service/impl/TaskKnowledgePointBaseServiceImpl.java

@ -0,0 +1,12 @@
package com.project.question.domain.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.question.domain.entity.TaskKnowledgePointEntity;
import com.project.question.domain.service.TaskKnowledgePointBaseService;
import com.project.question.mapper.TaskKnowledgePointMapper;
import org.springframework.stereotype.Service;
@Service
public class TaskKnowledgePointBaseServiceImpl extends ServiceImpl<TaskKnowledgePointMapper, TaskKnowledgePointEntity> implements TaskKnowledgePointBaseService {
}

4
src/main/java/com/project/task/mapper/TaskKnowledgeClusterMapper.java → src/main/java/com/project/question/mapper/TaskKnowledgeClusterMapper.java

@ -1,6 +1,6 @@
package com.project.task.mapper;
package com.project.question.mapper;
import com.project.task.domain.entity.TaskKnowledgeClusterEntity;
import com.project.question.domain.entity.TaskKnowledgeClusterEntity;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

4
src/main/java/com/project/task/mapper/TaskKnowledgePointMapper.java → src/main/java/com/project/question/mapper/TaskKnowledgePointMapper.java

@ -1,7 +1,7 @@
package com.project.task.mapper;
package com.project.question.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.task.domain.entity.TaskKnowledgePointEntity;
import com.project.question.domain.entity.TaskKnowledgePointEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper

19
src/main/java/com/project/task/config/TaskAsyncThreadPoolConfig.java

@ -11,7 +11,7 @@ import java.util.concurrent.ThreadPoolExecutor;
public class TaskAsyncThreadPoolConfig {
/**
* 1. 任务初始化池 (低频轮询专用)
* 任务初始化池 (低频轮询专用)
*/
@Bean(name = "taskInternalExecutor")
public Executor taskInternalExecutor() {
@ -25,21 +25,6 @@ public class TaskAsyncThreadPoolConfig {
return executor;
}
/**
* 2. 题目生成池 (高并发IO密集型)
* 核心允许并行处理不同的知识点
*/
@Bean(name = "questionGenExecutor")
public Executor questionGenExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 允许 5-10 个知识点同时进行 AI 出题
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("question-gen-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

2
src/main/java/com/project/task/domain/entity/ExamRecordEntity.java

@ -19,7 +19,7 @@ import java.util.List;
import java.util.Map;
@Data
@Table(name = "evaluator_exam_record" , indexes = {@Index(name = "Idx_parentId", columnList = "parent_id")})
@Table(name = "evaluator_exam_record")
@Entity
@TableName(value = "evaluator_exam_record" , autoResultMap = true)
@EqualsAndHashCode(callSuper = true)

2
src/main/java/com/project/task/domain/entity/TaskUserEntity.java

@ -12,7 +12,7 @@ import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
@Data
@Table(name = "evaluator_task_user" , indexes = {@Index(name = "Idx_parentId", columnList = "parent_id")})
@Table(name = "evaluator_task_user")
@Entity
@TableName(value = "evaluator_task_user" , autoResultMap = true)
@EqualsAndHashCode(callSuper = true)

2
src/main/java/com/project/task/domain/service/impl/InitTaskDomainServiceImpl.java

@ -7,7 +7,7 @@ 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.interactor.application.AlgorithmApplicationService;
import com.project.interaction.application.AlgorithmApplicationService;
import com.project.task.domain.service.InitTaskDomainService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

Loading…
Cancel
Save