|
|
|
@ -112,42 +112,56 @@ public class AssemblePaperDomainServiceImpl implements AssemblePaperDomainServic |
|
|
|
|
|
|
|
// 获取任务配置
|
|
|
|
TaskDTO taskDTO = taskBaseService.getById(taskId).toDTO(TaskDTO::new); |
|
|
|
int totalQuestionNum = taskDTO.getSingleChoiceNum() + taskDTO.getMultipleChoiceNum() + taskDTO.getTrueFalseNum(); |
|
|
|
// 权重乱序种子选取
|
|
|
|
List<TaskKnowledgePointDTO> seedKpList = selectWeightedSeedKpList(taskDTO, totalQuestionNum); |
|
|
|
// 本张试卷已覆盖的知识点ID集合
|
|
|
|
Set<Long> coveredKpPool = new HashSet<>(); |
|
|
|
// 最终选定题目
|
|
|
|
List<QuestionDTO> selectedQuestionList = new ArrayList<>(); |
|
|
|
// 分配种子:前N3个多选(过滤单知识点簇)
|
|
|
|
List<TaskKnowledgePointDTO> mcSeeds = seedKpList.stream() |
|
|
|
.filter(kp -> Objects.nonNull(kp.getClusterSize()) && kp.getClusterSize() > 1) |
|
|
|
.limit(taskDTO.getMultipleChoiceNum()) |
|
|
|
.toList(); |
|
|
|
//重新根据库存选取单选、判断
|
|
|
|
Set<Long> mcSeedIdSet = mcSeeds.stream().map(TaskKnowledgePointDTO::getId).collect(Collectors.toSet()); |
|
|
|
Set<Long> remainSeedIdSet = seedKpList.stream() |
|
|
|
.map(TaskKnowledgePointDTO::getId) |
|
|
|
.filter(id -> !mcSeedIdSet.contains(id)) |
|
|
|
.collect(Collectors.toSet()); |
|
|
|
|
|
|
|
List<TaskKnowledgePointDTO> remainSeedsBySupply = selectBySupply(taskDTO).stream() |
|
|
|
.filter(kp -> remainSeedIdSet.contains(kp.getId())) |
|
|
|
.toList(); |
|
|
|
List<TaskKnowledgePointDTO> scSeeds = remainSeedsBySupply.subList(0, Math.min(taskDTO.getSingleChoiceNum(), remainSeedsBySupply.size())); |
|
|
|
List<TaskKnowledgePointDTO> tfCandidateSeeds = remainSeedsBySupply.subList(scSeeds.size(), remainSeedsBySupply.size()); |
|
|
|
List<TaskKnowledgePointDTO> tfSeeds = remainSeedsBySupply.subList(0 , Math.min(taskDTO.getTrueFalseNum(), tfCandidateSeeds.size())); |
|
|
|
// 选择单选题
|
|
|
|
pickWithLock(scSeeds, QuestionTypeEnum.SINGLE_CHOICE , selectedQuestionList, coveredKpPool); |
|
|
|
// 选择判断题
|
|
|
|
pickWithLock(tfSeeds, QuestionTypeEnum.TRUE_FALSE , selectedQuestionList, coveredKpPool); |
|
|
|
|
|
|
|
pickMultipleQuestionsWithGreedy(mcSeeds , selectedQuestionList, coveredKpPool); |
|
|
|
selectedQuestionList.sort(Comparator.comparing(QuestionDTO::getQuestionType)); |
|
|
|
// 校验题数
|
|
|
|
if (selectedQuestionList.size() < totalQuestionNum) { |
|
|
|
throw new BusinessErrorException("当前题库可用题目不足,请联系管理员补货"); |
|
|
|
|
|
|
|
for (int attempt = 0; attempt < 5; attempt++) { |
|
|
|
int totalQuestionNum = taskDTO.getSingleChoiceNum() + taskDTO.getMultipleChoiceNum() + taskDTO.getTrueFalseNum(); |
|
|
|
// 权重乱序种子选取
|
|
|
|
List<TaskKnowledgePointDTO> seedKpList = selectWeightedSeedKpList(taskDTO, totalQuestionNum); |
|
|
|
// 本张试卷已覆盖的知识点ID集合
|
|
|
|
Set<Long> coveredKpPool = new HashSet<>(); |
|
|
|
// 分配种子:前N3个多选(过滤单知识点簇)
|
|
|
|
List<TaskKnowledgePointDTO> mcSeeds = seedKpList.stream() |
|
|
|
.filter(kp -> Objects.nonNull(kp.getClusterSize()) && kp.getClusterSize() > 1) |
|
|
|
.limit(taskDTO.getMultipleChoiceNum()) |
|
|
|
.toList(); |
|
|
|
//重新根据库存选取单选、判断
|
|
|
|
Set<Long> mcSeedIdSet = mcSeeds.stream().map(TaskKnowledgePointDTO::getId).collect(Collectors.toSet()); |
|
|
|
Set<Long> remainSeedIdSet = seedKpList.stream() |
|
|
|
.map(TaskKnowledgePointDTO::getId) |
|
|
|
.filter(id -> !mcSeedIdSet.contains(id)) |
|
|
|
.collect(Collectors.toSet()); |
|
|
|
|
|
|
|
List<TaskKnowledgePointDTO> remainSeedsBySupply = selectBySupply(taskDTO).stream() |
|
|
|
.filter(kp -> remainSeedIdSet.contains(kp.getId())) |
|
|
|
.toList(); |
|
|
|
List<TaskKnowledgePointDTO> scSeeds = remainSeedsBySupply.subList(0, Math.min(taskDTO.getSingleChoiceNum(), remainSeedsBySupply.size())); |
|
|
|
List<TaskKnowledgePointDTO> tfCandidateSeeds = remainSeedsBySupply.subList(scSeeds.size(), remainSeedsBySupply.size()); |
|
|
|
List<TaskKnowledgePointDTO> tfSeeds = remainSeedsBySupply.subList(0 , Math.min(taskDTO.getTrueFalseNum(), tfCandidateSeeds.size())); |
|
|
|
// 选择单选题
|
|
|
|
pickWithLock(scSeeds, QuestionTypeEnum.SINGLE_CHOICE , selectedQuestionList, coveredKpPool); |
|
|
|
// 选择判断题
|
|
|
|
pickWithLock(tfSeeds, QuestionTypeEnum.TRUE_FALSE , selectedQuestionList, coveredKpPool); |
|
|
|
|
|
|
|
pickMultipleQuestionsWithGreedy(mcSeeds , selectedQuestionList, coveredKpPool); |
|
|
|
|
|
|
|
// 校验:如果抽齐了,直接跳出重试循环
|
|
|
|
if (selectedQuestionList.size() >= totalQuestionNum) { |
|
|
|
break; |
|
|
|
} else { |
|
|
|
// 释放已占用的题目
|
|
|
|
if (!selectedQuestionList.isEmpty()) { |
|
|
|
List<Long> ids = selectedQuestionList.stream().map(QuestionDTO::getId).toList(); |
|
|
|
questionMapper.update(null, new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<QuestionEntity>() |
|
|
|
.set(QuestionEntity::getUseStatus, 0) |
|
|
|
.in(QuestionEntity::getId, ids)); |
|
|
|
} |
|
|
|
if (attempt == 4) throw new BusinessErrorException("当前题库可用题目不足,请联系管理员补货"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
selectedQuestionList.sort(Comparator.comparing(QuestionDTO::getQuestionType)); |
|
|
|
// 注册一个回调:在当前事务 commit 成功后,再触发异步补库
|
|
|
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
|
|
|
@Override |
|
|
|
|