背景
目前課時是沒有類型的我們希望針對課時增加類型的區分并且控制比例(例如: 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
, 根據占比數量生成對應的節點,如下:
image.png
image.png
如果節點分布過于分散,可能導致數據落點不均勻,如下圖最終分配 2 個 Major, 2 個 Trial。
image.png
所以要生成對應的虛擬節點,當教師放課時根據 課時信息的 Time 字段
生成 HASH 后落入以下節點中,最終落入節點的占比即為約課占比
真實節點
image.png
虛擬節點
image.png
HASH 環
最終得到 1 個 MAJOR,3 個 TRIAL,形成 3 : 1image.png
4. 通過 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