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