feat(复习):feed 智能模式——加权随机采样
- /review/feed?mode=smart:时间衰减 × 回忆掌握度加权采样 - 越久未见、回忆覆盖率越低的内容出现概率越高 - 保持随机性,符合复习模块偶遇式设计理念 - 概率性单元测试验证低掌握内容显著优先
This commit is contained in:
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
|
||||
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||
import com.guo.learningprogresstracker.entity.ReviewRecallRecordEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
|
||||
@@ -12,6 +13,7 @@ import com.guo.learningprogresstracker.entity.TaskEntity;
|
||||
import com.guo.learningprogresstracker.enums.ReviewMindMapFileFormatEnum;
|
||||
import com.guo.learningprogresstracker.enums.ReviewMindMapParseStatusEnum;
|
||||
import com.guo.learningprogresstracker.mapper.ReviewMindMapMapper;
|
||||
import com.guo.learningprogresstracker.mapper.ReviewRecallRecordMapper;
|
||||
import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper;
|
||||
import com.guo.learningprogresstracker.mapper.StudyReportsMapper;
|
||||
import com.guo.learningprogresstracker.mapper.StudySessionsMapper;
|
||||
@@ -67,6 +69,66 @@ class ReviewServiceImplTest {
|
||||
@Mock
|
||||
private ReviewMindMapMapper reviewMindMapMapper;
|
||||
|
||||
@Mock
|
||||
private ReviewRecallRecordMapper reviewRecallRecordMapper;
|
||||
|
||||
@Test
|
||||
void getReviewFeed_smartMode_prefersLowRecallRatioContent() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
StudyReportsEntity oldLowMastery = new StudyReportsEntity();
|
||||
oldLowMastery.setId(1);
|
||||
oldLowMastery.setSessionNum("S_LOW");
|
||||
oldLowMastery.setContent("很久没复习且掌握度低");
|
||||
oldLowMastery.setCreatedTime(now.minusDays(60));
|
||||
|
||||
StudyReportsEntity freshHighMastery = new StudyReportsEntity();
|
||||
freshHighMastery.setId(2);
|
||||
freshHighMastery.setSessionNum("S_HIGH");
|
||||
freshHighMastery.setContent("刚学完且掌握度高");
|
||||
freshHighMastery.setCreatedTime(now);
|
||||
|
||||
StudySessionsEntity sessionLow = new StudySessionsEntity();
|
||||
sessionLow.setSessionNum("S_LOW");
|
||||
sessionLow.setTaskNum("T_LOW");
|
||||
StudySessionsEntity sessionHigh = new StudySessionsEntity();
|
||||
sessionHigh.setSessionNum("S_HIGH");
|
||||
sessionHigh.setTaskNum("T_HIGH");
|
||||
|
||||
TaskEntity taskLow = new TaskEntity();
|
||||
taskLow.setTaskNum("T_LOW");
|
||||
taskLow.setTaskName("低掌握任务");
|
||||
TaskEntity taskHigh = new TaskEntity();
|
||||
taskHigh.setTaskNum("T_HIGH");
|
||||
taskHigh.setTaskName("高掌握任务");
|
||||
|
||||
ReviewRecallRecordEntity highRatioRecord = new ReviewRecallRecordEntity();
|
||||
highRatioRecord.setTaskNum("T_HIGH");
|
||||
highRatioRecord.setRecallRatio(1.0);
|
||||
highRatioRecord.setCreatedTime(now);
|
||||
|
||||
when(studyReportsMapper.selectList(any())).thenReturn(List.of(oldLowMastery, freshHighMastery));
|
||||
when(studyReportFragmentsMapper.selectList(any())).thenReturn(List.of());
|
||||
when(studySessionsMapper.selectList(any())).thenReturn(List.of(sessionLow, sessionHigh));
|
||||
when(tasksMapper.selectList(any())).thenReturn(List.of(taskLow, taskHigh));
|
||||
when(reviewRecallRecordMapper.selectList(any())).thenReturn(List.of(highRatioRecord));
|
||||
|
||||
List<ReviewFeedItem> items = reviewService.getReviewFeed(1, "smart");
|
||||
|
||||
// 采样是概率性的,多次运行统计低掌握内容被选中的频率应显著更高
|
||||
int lowMasteryWins = 0;
|
||||
for (int i = 0; i < 200; i++) {
|
||||
List<ReviewFeedItem> sample = reviewService.getReviewFeed(1, "smart");
|
||||
if (!sample.isEmpty() && "T_LOW".equals(sample.get(0).getTaskNum())) {
|
||||
lowMasteryWins++;
|
||||
}
|
||||
}
|
||||
assertEquals(1, items.size());
|
||||
// 低掌握内容权重约为高掌握内容的 5 倍以上,200 次中至少应赢 120 次
|
||||
org.junit.jupiter.api.Assertions.assertTrue(lowMasteryWins > 120,
|
||||
"低掌握内容被选中次数应显著更多,实际: " + lowMasteryWins + "/200");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getReviewFeed_shouldApplyFinalLimitAfterMerge() {
|
||||
StudyReportsEntity report = new StudyReportsEntity();
|
||||
|
||||
Reference in New Issue
Block a user