|
|
@@ -0,0 +1,179 @@
|
|
|
+package com.seecoder.dataanalysis.analysis.impl;
|
|
|
+
|
|
|
+import cn.seecoder.bok.common.vo.QuestionVO;
|
|
|
+import com.seecoder.dataanalysis.analysis.EvalDataAnalysisService;
|
|
|
+import com.seecoder.dataanalysis.analysis.RecommandService;
|
|
|
+import com.seecoder.dataanalysis.data.dao.competency.CompetencyTreeDao;
|
|
|
+import com.seecoder.dataanalysis.data.entity.competency.CompetencyTree;
|
|
|
+import com.seecoder.dataanalysis.data.entity.competency.KSDScore;
|
|
|
+import com.seecoder.dataanalysis.logic.question.QuestionService;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class RecommandServiceImpl implements RecommandService {
|
|
|
+ //默认推荐的题目数量
|
|
|
+ public static final int QUESTION_NUM = 30;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EvalDataAnalysisService evalDataAnalysisService;
|
|
|
+ @Autowired
|
|
|
+ private QuestionService questionService;
|
|
|
+ @Autowired
|
|
|
+ private CompetencyTreeDao competencyTreeDao;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<QuestionVO> getRecommandById(int userId){
|
|
|
+ Random random = new Random();
|
|
|
+ //获取学生的做题情况
|
|
|
+ Map<String,Double> errorQuestions = evalDataAnalysisService.getStudentErrorQuestions(userId);
|
|
|
+ //学生的错题列表,只存储0分的题目
|
|
|
+ //本次只考虑SR类型的错题,其他都不添加
|
|
|
+ //TODO 针对多个知识点的情况
|
|
|
+ String target = "SR";
|
|
|
+ List<String> errors = new ArrayList<>();
|
|
|
+ for(Map.Entry<String,Double> entry : errorQuestions.entrySet()){
|
|
|
+ String questionId = entry.getKey();
|
|
|
+ if(entry.getValue().equals(0.0)){
|
|
|
+ List<String> ks = questionService.getKnowledgesById(questionId);
|
|
|
+ for(String k : ks){
|
|
|
+ if(k.contains(target)){
|
|
|
+ errors.add(questionId);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CompetencyTree competencyTree;
|
|
|
+ //获取学生的能力树
|
|
|
+ Optional<CompetencyTree> result = competencyTreeDao.findById(userId);
|
|
|
+ if(!result.isPresent()){
|
|
|
+ competencyTree = new CompetencyTree(userId);
|
|
|
+ }else {
|
|
|
+ competencyTree = competencyTreeDao.findById(userId).get();
|
|
|
+ }
|
|
|
+ //先推荐没做过的(没做过的类型再到同类型没做过的题目),再推荐分支中分数低的
|
|
|
+ //本次题目都是SR类的,所以只查看SR分支
|
|
|
+ List<String> tarKnows = new ArrayList<>();
|
|
|
+ tarKnows.add("SR");
|
|
|
+ //每种类型推荐多少题目,由知识点数目而定
|
|
|
+ int eachNum = QUESTION_NUM / tarKnows.size();
|
|
|
+ //知识点和对应分数
|
|
|
+ Map<String,Double> knowlegdeAndScores = new HashMap<>();
|
|
|
+ for(String tarKnow :tarKnows){
|
|
|
+ String[] tars = tarKnow.split("\\.");
|
|
|
+ List<KSDScore> ksdScoreList = competencyTree.getSubCompetencyTree();
|
|
|
+ for(KSDScore ksdScore : ksdScoreList){
|
|
|
+ //先匹配最外层
|
|
|
+ if(ksdScore.getCompetency().equals(tars[0])){
|
|
|
+ if(!knowlegdeAndScores.containsKey(tars[0])){
|
|
|
+ knowlegdeAndScores.put(tars[0],ksdScore.getTotalScore());
|
|
|
+ }
|
|
|
+ //再匹配第二层
|
|
|
+ //TODO 完善匹配机制
|
|
|
+ if(tars.length>1){}
|
|
|
+ //将分支下所有子分支都添加
|
|
|
+ if(ksdScore.getChildren()!=null&&ksdScore.getChildren().size()>0){
|
|
|
+ for(KSDScore subKSD1 : ksdScore.getChildren()){
|
|
|
+ if(!knowlegdeAndScores.containsKey(subKSD1.getCompetency())){
|
|
|
+ knowlegdeAndScores.put(subKSD1.getCompetency(),subKSD1.getTotalScore());
|
|
|
+ }
|
|
|
+ if(subKSD1.getChildren()!=null&&subKSD1.getChildren().size()>0){
|
|
|
+ for(KSDScore subKSD2 : subKSD1.getChildren()){
|
|
|
+ if(!knowlegdeAndScores.containsKey(subKSD2.getCompetency())){
|
|
|
+ knowlegdeAndScores.put(subKSD2.getCompetency(),subKSD2.getTotalScore());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Map.Entry<String,Double>> list = new ArrayList<>(knowlegdeAndScores.entrySet());
|
|
|
+ Collections.sort(list,(a,b)->(int)((double)a.getValue()-(double)b.getValue()));
|
|
|
+ //根据得分升序排列,得到学生相对薄弱的部分
|
|
|
+ Map<String,Double> afterSort = new LinkedHashMap<>();
|
|
|
+ for(Map.Entry<String,Double> o : list){
|
|
|
+ afterSort.put(o.getKey(),o.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+// for(Map.Entry<String,Double> entry : afterSort.entrySet()){
|
|
|
+// System.out.println(entry.getKey()+": "+entry.getValue());
|
|
|
+// }
|
|
|
+
|
|
|
+ //还需要添加的题目数目,姑且设计为5错题+15低分+10大类中未做过的,剩下不足的由未做过的题目补充
|
|
|
+ int left = QUESTION_NUM;
|
|
|
+ //最终生成试卷的所有题号的集合
|
|
|
+ List<String> total = new ArrayList<>();
|
|
|
+
|
|
|
+ //随机选择5道错题
|
|
|
+ for(int i=0;errors.size()>0&&i<5;i++){
|
|
|
+ int r = random.nextInt(errors.size());
|
|
|
+ total.add(errors.get(r));
|
|
|
+ left--;
|
|
|
+ errors.remove(errors.get(r));
|
|
|
+ }
|
|
|
+
|
|
|
+ //随机选择10道和低分类似类似的题目
|
|
|
+ List<String> similar = new ArrayList<>();
|
|
|
+ int index = 0;
|
|
|
+ for(Map.Entry<String,Double> entry : afterSort.entrySet()){
|
|
|
+ if(index>=5){
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ String tar = entry.getKey();
|
|
|
+ if(tar.split("\\.").length>1){
|
|
|
+ List<String> ks = new ArrayList<>();
|
|
|
+ ks.add(tar);
|
|
|
+ List<QuestionVO> questions = questionService.searchQuestions(ks);
|
|
|
+ for(QuestionVO questionVO : questions){
|
|
|
+ String questionId = questionVO.getId();
|
|
|
+ if(total.contains(questionId)==false && similar.contains(questionId)==false){
|
|
|
+ similar.add(questionId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ //随机选择15道相似题目
|
|
|
+ for(int i=0;similar.size()>0&&i<15;i++){
|
|
|
+ int r = random.nextInt(similar.size());
|
|
|
+ total.add(similar.get(r));
|
|
|
+ left--;
|
|
|
+ similar.remove(similar.get(r));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //从大类中随机选择剩下的所有题目
|
|
|
+ List<QuestionVO> questions = questionService.searchQuestions(tarKnows);
|
|
|
+ List<String> undos = new ArrayList<>();
|
|
|
+ for(QuestionVO questionVO : questions){
|
|
|
+ String questionId = questionVO.getId();
|
|
|
+ if(total.contains(questionId)==false){
|
|
|
+ undos.add(questionId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while(undos.size()>0 && left > 0){
|
|
|
+ int r = random.nextInt(undos.size());
|
|
|
+ total.add(undos.get(r));
|
|
|
+ left--;
|
|
|
+ undos.remove(undos.get(r));
|
|
|
+ }
|
|
|
+
|
|
|
+ for(String s : total){
|
|
|
+ System.out.println(s);
|
|
|
+ }
|
|
|
+ System.out.println(total.size());
|
|
|
+
|
|
|
+ List<QuestionVO> res = new ArrayList<>();
|
|
|
+
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+}
|