前言
大数据统计中的频率估计问题,即求一个元素出现的次数。和Cardinality Estimation场景相似,面临着内存开销大的问题,不适合直接存储原始数据。本篇文章介绍解决这个问题的一个算法,Count-Min Sketch 。
算法
Count-Min Sketch 算法是在论文An Improved Data Stream Summary:
The Count-Min Sketch and its Applications中阐述的,下面介绍的算法流程及精度均参考自该论文,相关证明请参考原文。
流程
算法流程:
- 创建二维数组,count[d, w],每一位初始化为0。
- d个hash函数, h 1 h_1 h1 . . . h d h_d hd : {1 . . . n} → {1 . . . w}。
- 输入元素( i t i_t it, c t c_t ct),更新二维数组:count[ j j j, h j h_j hj ( i t i_t it)] ← count[ j j j, h j h_j hj( i t i_t it)] + c t c_t ct,此过程如上图所示。
- 查询某个元素出现频率,等于 min j j j count[ j j j, h j h_j hj( i i i)]。
简单理解,Count-Min Sketch算法使用d个长度为w的一维数组,对于每个输入元素( i t i_t it, c t c_t ct),分别用d个hash函数处理,每个hash函数的处理结果进入对应的一维数组w的位置,如上图所示。由于hash函数的使用,不同元素会产生冲突,导致统计增大,为了减少这种误差,取二维数组count[ j j j, h j h_j hj( i i i)]的最小值。
精度
从上面的算法流程中,可以初略看出,二维数组的d和w越大,hash冲突的概率越低,结果的精度也越高。论文An Improved Data Stream Summary:
The Count-Min Sketch and its Applications也给出了相应的结论和证明,这里我们仅看下结论
- 最小值
如上图(取自论文),我们取数组count[ j j j, h j h_j hj( i i i)]的最小值估算元素出现频率时,有1 − δ的信心, a ˆ i aˆ_i aˆi ≤ a i a_i ai + ε ∣ ∣ a ∣ ∣ 1 ε||a||_1 ε∣∣a∣∣1。
上面的δ和ε跟二维数组中的d和w相关,如下
- 中位数
论文中还给出了一个和数组count[ j j j, h j h_j hj( i i i)]中位数相关的结论,如下
实现及改进
实现
Count-Min Sketch的实现可以参考stream-lib CountMinSketch.java和stream-lib ConservativeAddSketch.java,ConservativeAddSketch做了点优化,更新时不只是count[ j j j, h j h_j hj( i t i_t it)] + c t c_t ct,不详解,查看代码。
改进
Count-Min Sketch算法的改进版本非常多,可以参考这篇Sketch调研。
参考:
1.An Improved Data Stream Summary: The Count-Min Sketch and its Applications
2.stream-lib CountMinSketch.java
3.stream-lib ConservativeAddSketch.java
4.Sketch调研