# 078. 在 storm 拓扑中加入热点缓存实时自动识别和感知的代码逻辑
思路:
- 对商品访问次数 LRUMap 中的所有数据进行排序
- 计算后 95% 商品平均访值
- 对前 5% 的商品进行热点阈值评估,大于 n 倍的视为热点商品,存储在热点商品列表中
下面用代码来实现这个逻辑
/**
* 热点商品感知
*/
private static class HotProductFindThread extends Thread {
private Logger logger = LoggerFactory.getLogger(getClass());
private LRUMap<Long, Long> countMap;
public HotProductFindThread(LRUMap<Long, Long> countMap) {
this.countMap = countMap;
}
@Override
public void run() {
List<Map.Entry<Long, Long>> countList = new ArrayList<>();
List<Long> hotPidList = new ArrayList<>();
while (true) {
Utils.sleep(5000);
if (countMap.size() < 2) {
// 至少有 2 个商品
continue;
}
// 1. 全局排序
countList.clear();
hotPidList.clear();
for (Map.Entry<Long, Long> entry : countMap.entrySet()) {
countList.add(entry);
}
Collections.sort(countList, new Comparator<Map.Entry<Long, Long>>() {
@Override
public int compare(Map.Entry<Long, Long> o1, Map.Entry<Long, Long> o2) {
// 取反结果,是降序排列
return ~Long.compare(o1.getValue(), o2.getValue());
}
});
// 2.计算后 95% 商品平均访值
int avg95Count = (int) (countList.size() * 0.95);
int avg95Total = 0;
// 从列表尾部开始循环 avg95Count 次
for (int i = countList.size() - 1; i >= countList.size() - avg95Count; i--) {
avg95Total += countList.get(i).getValue();
}
// 后百分之 95 商品的平均访问值
int avg95Avg = avg95Total / avg95Count;
int threshold = 5; // 阈值
// 3. 计算热点商品
for (int i = 0; i < avg95Count; i++) {
Map.Entry<Long, Long> entry = countList.get(i);
if (entry.getValue() > avg95Avg * threshold) {
logger.info("热点商品:" + entry);
hotPidList.add(entry.getKey());
}
}
logger.info("热点商品列表:" + hotPidList);
}
}
public static void main(String[] args) {
LRUMap<Long, Long> countMap = new LRUMap<>(5);
countMap.put(1L, 2L);
countMap.put(2L, 1L);
countMap.put(3L, 3L);
countMap.put(4L, 30L);
// 最后打印 4L 是热点商品,这个结果是对的
new HotProductFindThread(countMap).run();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
吸取上一章节的教训,这次写完一个小模块,就测试下逻辑是否正常。