| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- 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<String> getRecommendById(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<KSDScore> 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<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错题+5错题同类型题+15低分能力下的题目+5大类中未做过的,剩下不足的由未做过的题目补充
- 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));
- }
- //随机选择5道和错题知识点相同的题目
- List<String> errKnows = new ArrayList<>();
- for(int i=0;i<total.size();i++){
- List<String> 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<String> search = new ArrayList<>();
- search.add(know);
- List<QuestionVO> 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<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());
- return total;
- }
- }
|