|
@@ -44,8 +44,23 @@ public class PaperService {
|
|
|
this.questionsMapper = questionsMapper;
|
|
this.questionsMapper = questionsMapper;
|
|
|
this.learnQuestionsService = learnQuestionsService;
|
|
this.learnQuestionsService = learnQuestionsService;
|
|
|
this.learnDirectedKnowledgeMapper = learnDirectedKnowledgeMapper;
|
|
this.learnDirectedKnowledgeMapper = learnDirectedKnowledgeMapper;
|
|
|
- // buildSimulatedPaper(20154L, 11L);
|
|
|
|
|
this.wishUniversitiesService = wishUniversitiesService;
|
|
this.wishUniversitiesService = wishUniversitiesService;
|
|
|
|
|
+ // buildSimulatedPaper(20154L, 11L);
|
|
|
|
|
+ // test2();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void test2() {
|
|
|
|
|
+ TestPaperVO.PaperDef paperDef = new TestPaperVO.PaperDef();
|
|
|
|
|
+ paperDef.setFillExclude(true);
|
|
|
|
|
+ paperDef.setKnowIds(Lists.newArrayList(1016L,1101L,1091L, 1103L));
|
|
|
|
|
+ List<TestPaperVO.TypeDef> typeDefList= Lists.newArrayList();
|
|
|
|
|
+ typeDefList.add(new TestPaperVO.TypeDef("判断题", "判断题", 20, 2));
|
|
|
|
|
+ typeDefList.add(new TestPaperVO.TypeDef("单选题", "单选题", 10, 1));
|
|
|
|
|
+ typeDefList.add(new TestPaperVO.TypeDef("多选题", "多选题", 10, 2));
|
|
|
|
|
+ paperDef.setTypes(typeDefList);
|
|
|
|
|
+ paperDef.setTotal(40L);
|
|
|
|
|
+ List<LearnPaperQuestion> questionList = getQuestionsByType(null, paperDef);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void test() {
|
|
public void test() {
|
|
@@ -114,6 +129,8 @@ public class PaperService {
|
|
|
} else {
|
|
} else {
|
|
|
BeanUtils.copyProperties(lqs, qs, "title", "options", "parse", "answer1", "answer2");
|
|
BeanUtils.copyProperties(lqs, qs, "title", "options", "parse", "answer1", "answer2");
|
|
|
}
|
|
}
|
|
|
|
|
+ qs.setTotalScore(lqs.getScore());
|
|
|
|
|
+ qs.setScore(null);
|
|
|
QuestionType qt = QuestionType.of(lqs.getQtpye());
|
|
QuestionType qt = QuestionType.of(lqs.getQtpye());
|
|
|
qs.setTypeId(qt.getVal());
|
|
qs.setTypeId(qt.getVal());
|
|
|
qs.setIsFavorite(lqs.isCollect());
|
|
qs.setIsFavorite(lqs.isCollect());
|
|
@@ -123,6 +140,7 @@ public class PaperService {
|
|
|
qs.setState(answer.getState());
|
|
qs.setState(answer.getState());
|
|
|
qs.setIsMark(answer.getMark());
|
|
qs.setIsMark(answer.getMark());
|
|
|
qs.setIsNotKnow(answer.getNotKnow());
|
|
qs.setIsNotKnow(answer.getNotKnow());
|
|
|
|
|
+ qs.setScore(answer.getScore());
|
|
|
}
|
|
}
|
|
|
if(StringUtils.isNotBlank(lqs.getTitle0())) { // 大题
|
|
if(StringUtils.isNotBlank(lqs.getTitle0())) { // 大题
|
|
|
PaperVO.QuestionAnswer qg = gropuMap.get(lqs.getTitle0());
|
|
PaperVO.QuestionAnswer qg = gropuMap.get(lqs.getTitle0());
|
|
@@ -229,6 +247,19 @@ public class PaperService {
|
|
|
return paper;
|
|
return paper;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 按类型,知识点平均分配组卷
|
|
|
|
|
+ * @param studentId
|
|
|
|
|
+ * @param paperDef
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public List<LearnPaperQuestion> getQuestionsByType(Long studentId, TestPaperVO.PaperDef paperDef) {
|
|
|
|
|
+ // 统计知识点+类型的有效数量 TODO 总量可以缓存
|
|
|
|
|
+ Map<String, KnowTypeAssign> knowTypeAssignMap = buildKnowTypeAssignMap(studentId, paperDef);
|
|
|
|
|
+ assignTypeFirstWithCount(paperDef, knowTypeAssignMap); // 知识优先,类型可变
|
|
|
|
|
+ return getQuestions(studentId, paperDef, knowTypeAssignMap);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 按知识点,题型平均分配组卷
|
|
* 按知识点,题型平均分配组卷
|
|
|
* @param studentId
|
|
* @param studentId
|
|
@@ -243,6 +274,188 @@ public class PaperService {
|
|
|
return getQuestions(studentId, paperDef, knowTypeAssignMap);
|
|
return getQuestions(studentId, paperDef, knowTypeAssignMap);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void assignTypeFirstWithCount(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
|
|
|
|
|
+ AtomicLong assignCount = new AtomicLong(0);
|
|
|
|
|
+ Map<Long, Long> knownAdjMap = Maps.newHashMap();
|
|
|
|
|
+ Map<String, Set<Long>> typeKnowIdMap = Maps.newHashMap();
|
|
|
|
|
+ Map<String, Long> typeFillCntMap = Maps.newHashMap();
|
|
|
|
|
+ Map<String, Long> typeMinCntMap = Maps.newHashMap();
|
|
|
|
|
+ // 所有知识点,正常补全一次,哪个知识点差多少先记录下
|
|
|
|
|
+ for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
|
|
|
|
|
+ Long avgKnowTypeCount = typeDef.getCount().longValue() / paperDef.getKnowIds().size();
|
|
|
|
|
+ if(avgKnowTypeCount.equals(0L)) {
|
|
|
|
|
+ avgKnowTypeCount = 1L;
|
|
|
|
|
+ }
|
|
|
|
|
+ assignCount.set(0);
|
|
|
|
|
+ for(Long knowId : paperDef.getKnowIds()) {
|
|
|
|
|
+ Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, avgKnowTypeCount, paperDef.getFillExclude(), assignCount);
|
|
|
|
|
+ if (tmpMinKnowTypeCount > 0) {
|
|
|
|
|
+ // 记录最小数
|
|
|
|
|
+ Long minKnowTypeCount = typeMinCntMap.get(typeDef.getType());
|
|
|
|
|
+ typeMinCntMap.put(typeDef.getType(), null == minKnowTypeCount ? tmpMinKnowTypeCount : Math.min(minKnowTypeCount, tmpMinKnowTypeCount));
|
|
|
|
|
+ // 记录有效知识点
|
|
|
|
|
+ Set<Long> knownIdSet = typeKnowIdMap.get(typeDef.getType());
|
|
|
|
|
+ if(null == knownIdSet) {
|
|
|
|
|
+ typeKnowIdMap.put(typeDef.getType(), Sets.newHashSet(knowId));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ knownIdSet.add(knowId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
|
|
|
|
|
+ // 记录知识点差额
|
|
|
|
|
+ Long lackCount = knownAdjMap.get(knowId);
|
|
|
|
|
+ knownAdjMap.put(knowId, (null != lackCount ? lackCount : 0L) - tmpMinKnowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ typeFillCntMap.put(typeDef.getType(), assignCount.get());
|
|
|
|
|
+ }
|
|
|
|
|
+ knownAdjMap.clear();
|
|
|
|
|
+ // 优先补充差的知识点
|
|
|
|
|
+ for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
|
|
|
|
|
+ assignCount.set(typeFillCntMap.get(typeDef.getType()));
|
|
|
|
|
+ Long lackTotal = typeDef.getCount().longValue();
|
|
|
|
|
+ Long minCount = typeMinCntMap.get(typeDef.getType());
|
|
|
|
|
+ Set<Long> knownIdSet = typeKnowIdMap.get(typeDef.getType());
|
|
|
|
|
+ do {
|
|
|
|
|
+ if(lackTotal <= assignCount.get()) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ Long needCount = lackTotal - assignCount.get();
|
|
|
|
|
+ Long avgKnowTypeCount = knownIdSet.size() > 0 ? Math.min(minCount, needCount / knownIdSet.size()) : 1;
|
|
|
|
|
+ if (avgKnowTypeCount <= 0L) {
|
|
|
|
|
+ avgKnowTypeCount = 1L;
|
|
|
|
|
+ }
|
|
|
|
|
+ minCount = Long.MAX_VALUE;
|
|
|
|
|
+ Set<Long> validIdSet = Sets.newHashSet(knownIdSet);
|
|
|
|
|
+ knownIdSet.clear();
|
|
|
|
|
+ for(Long knowId : paperDef.getKnowIds()) {
|
|
|
|
|
+ if(knownIdSet.size() > 0 && !validIdSet.contains(knowId)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ // Long lastLack = null; knownAdjMap.remove(knowId); null != lastLack ? lastLack + avgKnowTypeCount :
|
|
|
|
|
+ Long knowTypeCount = avgKnowTypeCount;
|
|
|
|
|
+ if (knowTypeCount > 0) {
|
|
|
|
|
+// Long oldCnt = assignCount.get();
|
|
|
|
|
+ Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
|
|
|
|
|
+// Long fillCnt = oldCnt - assignCount.get();
|
|
|
|
|
+// if(fillCnt < 0) {
|
|
|
|
|
+// Long oldFill = knownAdjMap.get(knowId);
|
|
|
|
|
+// knownAdjMap.put(knowId, null == oldFill ? fillCnt : oldFill - fillCnt);
|
|
|
|
|
+// }
|
|
|
|
|
+ if (tmpMinKnowTypeCount > 0) {
|
|
|
|
|
+ minCount = Math.min(minCount, tmpMinKnowTypeCount);
|
|
|
|
|
+ knownIdSet.add(knowId);
|
|
|
|
|
+ } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
|
|
|
|
|
+ // knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if(knowTypeCount < 0) {
|
|
|
|
|
+ // knownAdjMap.put(knowId, knowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ if(lackTotal <= assignCount.get()) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } while(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void assignTypeFirstWithCount2(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
|
|
|
|
|
+ Map<String, Set<Long>> typeKnownIdsMap = knowTypeAssignMap.values().stream().collect(Collectors.groupingBy(KnowTypeAssign::getType, Collectors.mapping(KnowTypeAssign::getKnowId, Collectors.toSet())));
|
|
|
|
|
+ Map<Long, Long> knownAdjMap = Maps.newHashMap();
|
|
|
|
|
+ AtomicLong assignCount = new AtomicLong(0);
|
|
|
|
|
+ Integer needCount = paperDef.getTypes().size();
|
|
|
|
|
+ Set<String> doneSet = Sets.newHashSet();
|
|
|
|
|
+ do {
|
|
|
|
|
+ for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) { // 每个类型,让所有知识先平均补充,补充的由后面填充
|
|
|
|
|
+ Long minKnowTypeCount = Long.MAX_VALUE;
|
|
|
|
|
+ // 首先按平均数量填充
|
|
|
|
|
+ assignCount.set(0L);
|
|
|
|
|
+ Long lackTotal = typeDef.getCount().longValue();
|
|
|
|
|
+ Set<Long> knownIdSet;
|
|
|
|
|
+ if(knownAdjMap.size() > 0) { // 先补充之前的同类型
|
|
|
|
|
+ knownIdSet = Sets.newHashSet();
|
|
|
|
|
+ for(Long knowId : paperDef.getKnowIds()) {
|
|
|
|
|
+ Long lastLack = knownAdjMap.remove(knowId);
|
|
|
|
|
+ Long knowTypeCount = null != lastLack ? lastLack : 0;
|
|
|
|
|
+ if(knowTypeCount >= 0) {
|
|
|
|
|
+ Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
|
|
|
|
|
+ if (tmpMinKnowTypeCount > 0) {
|
|
|
|
|
+ minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
|
|
|
|
|
+ knownIdSet.add(knowId);
|
|
|
|
|
+ } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
|
|
|
|
|
+ knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if(knowTypeCount < 0) {
|
|
|
|
|
+ knownAdjMap.put(knowId, knowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ knownIdSet = typeKnownIdsMap.get(typeDef.getType());
|
|
|
|
|
+ }
|
|
|
|
|
+ if(lackTotal <= assignCount.get()) {
|
|
|
|
|
+ doneSet.add(typeDef.getType());
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Long avgKnowTypeCount = (lackTotal - assignCount.get()) / paperDef.getKnowIds().size();
|
|
|
|
|
+ if (avgKnowTypeCount <= 0L) {
|
|
|
|
|
+ avgKnowTypeCount = 1L;
|
|
|
|
|
+ }
|
|
|
|
|
+ for(Long knowId : paperDef.getKnowIds()) {
|
|
|
|
|
+ Long lastLack = knownAdjMap.remove(knowId);
|
|
|
|
|
+ Long knowTypeCount = null != lastLack ? lastLack + avgKnowTypeCount : avgKnowTypeCount;
|
|
|
|
|
+ if(knowTypeCount > 0) {
|
|
|
|
|
+ Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
|
|
|
|
|
+ if (tmpMinKnowTypeCount > 0) {
|
|
|
|
|
+ minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
|
|
|
|
|
+ knownIdSet.add(knowId);
|
|
|
|
|
+ } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
|
|
|
|
|
+ knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if(knowTypeCount < 0) {
|
|
|
|
|
+ knownAdjMap.put(knowId, knowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 然后进行多级补充,多退少补
|
|
|
|
|
+ do {
|
|
|
|
|
+ if(lackTotal <= assignCount.get()) {
|
|
|
|
|
+ doneSet.add(typeDef.getType());
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ avgKnowTypeCount = Math.min(minKnowTypeCount, (lackTotal - assignCount.get()) / knownIdSet.size());
|
|
|
|
|
+ if (avgKnowTypeCount <= 0L) {
|
|
|
|
|
+ avgKnowTypeCount = 1L;
|
|
|
|
|
+ }
|
|
|
|
|
+ minKnowTypeCount = Long.MAX_VALUE;
|
|
|
|
|
+ Set<Long> validIdSet = Sets.newHashSet(knownIdSet);
|
|
|
|
|
+ knownIdSet.clear();
|
|
|
|
|
+ for(Long knowId : paperDef.getKnowIds()) {
|
|
|
|
|
+ if(!validIdSet.contains(knowId)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Long lastLack = knownAdjMap.remove(knowId);
|
|
|
|
|
+ Long knowTypeCount = null != lastLack ? lastLack + avgKnowTypeCount : avgKnowTypeCount;
|
|
|
|
|
+ if (knowTypeCount > 0) {
|
|
|
|
|
+ Long oldCnt = assignCount.get();
|
|
|
|
|
+ Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
|
|
|
|
|
+ Long fillCnt = oldCnt - assignCount.get();
|
|
|
|
|
+ if(fillCnt < 0) {
|
|
|
|
|
+ Long oldFill = knownAdjMap.get(knowId);
|
|
|
|
|
+ knownAdjMap.put(knowId, null == oldFill ? fillCnt : oldFill - fillCnt);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (tmpMinKnowTypeCount > 0) {
|
|
|
|
|
+ minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
|
|
|
|
|
+ knownIdSet.add(knowId);
|
|
|
|
|
+ } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
|
|
|
|
|
+ knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if(knowTypeCount < 0) {
|
|
|
|
|
+ knownAdjMap.put(knowId, knowTypeCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } while(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ } while(doneSet.size() < needCount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private void assignKnowFirst(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
|
|
private void assignKnowFirst(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
|
|
|
// 循环补充未做+已做,如果知识点总数不够时才填充其他知识点的
|
|
// 循环补充未做+已做,如果知识点总数不够时才填充其他知识点的
|
|
|
Long lackTotal = paperDef.getTotal();
|
|
Long lackTotal = paperDef.getTotal();
|
|
@@ -440,7 +653,7 @@ public class PaperService {
|
|
|
} else if(lack < 0) {
|
|
} else if(lack < 0) {
|
|
|
return -lack;
|
|
return -lack;
|
|
|
}
|
|
}
|
|
|
- return 0L;
|
|
|
|
|
|
|
+ return -lack;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|