背景
目前课时是没有类型的我们希望针对课时增加类型的区分并且控制比例(例如: TRIAL / MAJOR = 3 / 1)
要求
- 不通过数据库记录已存在的课时类型信息
- 要保证增加 1 课时后,之前的课时类型尽量保持不变
- 当类型占比设置发生变化时,数据移动最小
结论
选用第 4 种方案目前测试结果第 3、4 种方案效果较好,但从简易实现程度和比例控制来看,选用第 4 种方案更佳。
划分方案
1. 按时间顺序划分
image.png弊端
- 按时间顺序分:时间不均衡,可能导致 TRIAL 课集中在前几天,后面两天想约 TRIAL 约不到
2. 按时间均分
image.png弊端
- 按时间均分: 比例调整后,划分位置变动较大
以下两种方式是通过对
课时信息的 Time 字段
进行 HASH 并排序后进行类型划分好处: 可以尽量保证新课时加入集合中后,集合中已存在的课时类型变化最小
3. 通过一致性 Hash 环划分
什么是 一致性 Hash 环?一致性哈希算法
占比之和等于总节点数
,比如 TRIAL / MJAOR 为 3 / 1
, 根据占比数量生成对应的节点,如下:
如果节点分布过于分散,可能导致数据落点不均匀,如下图最终分配 2 个 Major, 2 个 Trial。
image.png所以要生成对应的虚拟节点,当教师放课时根据 课时信息的 Time 字段
生成 HASH 后落入以下节点中,最终落入节点的占比即为约课占比
真实节点
image.png虚拟节点
image.pngHASH 环
最终得到 1 个 MAJOR,3 个 TRIAL,形成 3 : 1 image.png4. 通过 HASH 散列并排序后按比例切分
这个方案是拿到一个课时集合,比如:
"2019-01-14 18:30:00"
"2019-01-14 19:00:00"
"2019-01-15 18:30:00"
"2019-01-15 19:30:00"
把以上集合直接放入 HashSet 得到一个无序的列表
"2019-01-14 18:30:00"
"2019-01-15 19:30:00"
"2019-01-14 19:00:00"
"2019-01-15 18:30:00"
之后按照比例,如:3 / 1 , 分割后得到:
TRIAL:
"2019-01-14 18:30:00"
"2019-01-15 19:30:00"
"2019-01-14 19:00:00"
MAJOR:
"2019-01-15 18:30:00"
实例代码如下:
double trialRatio = 3;
double majorRatio = 1;
String[] keys = {
"2019-01-14 18:30:00"
, "2019-01-14 19:00:00"
, "2019-01-15 18:30:00"
, "2019-01-15 19:30:00"
};
HashSet<String> hashSet = new HashSet<>(keys);
List<String> timeList = Lists.newArrayList(hashSet);
double t = Math.round((double) keys.length / (trialRatio + majorRatio) * trialRatio);
System.out.println("\nTRIAL 课");
timeList.subList(0, (int)t).forEach(System.out::println);
System.out.println("\nMAJOR 课");
timeList.subList((int)t, timeList.size()).forEach(System.out::println);
参考链接:
一致性哈希算法的理解与实践
Consistent_hashing
Consistent Hashing in Cassandra
网友评论