背景描述:
对于每一个不同的用户,从题库里随机抽取题目, 抽取的题目都是该用户未抽取过的,每个用户产生的考卷不相同。
解决方案:
方法一:使用bitSet保存用户历史题集
内存占用分析:百万级用户*万级题目量=100GB
缺点: bitSet持久化比较麻烦
方法二:哈希
选取一个大于题库总数的最小质数p, 对每个用户生成独特哈希函数
h a b ( x ) = ( a x + b ) m o d p ( 0 < a < p , 0 ≤ b < p ) h_{ab}(x) = (ax+b)mod\ p\qquad(0<a<p, 0 \le b <p) hab(x)=(ax+b)mod p(0<a<p,0≤b<p)
可以证明, 对于不同的x,y<p, h a b ( x ) ≠ h a b ( y ) h_{ab}(x) \ne h_{ab}(y) hab(x)=hab(y)
那么对于每个用户, 保存a,b,x
x是每次递增1的做题进度, 通过哈希函数生成下一题号, 生成题号大于总题数m则跳过.
public class RandomQuestion {
private static class QuestionBank {
// 题库数量
private static int QUESTION_SUM = 50;
// 大于题库总数的最小质数p
private static int P = 53;
public static int getUserNextQuestion(User u) {
int next = u.getNext(P);
if (next > QUESTION_SUM) {
return getUserNextQuestion(u);
}
return next;
}
}
private static class User {
private int a;
private int b;
private int current;
public User(int a, int b) {
this.a = a;
this.b = b;
this.current = 0;
}
public int getNext(int p) {
return Math.floorMod((a * current++ + b), p);
}
}
public static void main(String[] args) {
User a = new User(new Random().nextInt(), new Random().nextInt());
User b = new User(new Random().nextInt(), new Random().nextInt());
System.out.println("user a:");
for (int i = 0; i < 50; i++) {
System.out.print(QuestionBank.getUserNextQuestion(a) + " ");
}
System.out.println("\nuser b:");
for (int i = 0; i < 50; i++) {
System.out.print(QuestionBank.getUserNextQuestion(b) + " ");
}
}
}
问题延伸
- 如何处理题库增加题目的问题,用户不受影响的问题,质数D选个大一点的,这样C可以直接增加,或者是是参考一致性哈希的思想
- 问题添加权重,高优问题优先展示
- 问题添加难度系数,生成的每份考卷难度系数之和在某个范围