frequency-estimation
如何计算数据流中任意元素的频率?
这个问题也是大数据场景下的一个经典问题,称为频率估计
方案1: HashMap
用一个
方案2: 数据分片+ HashMap
既然单机内存存不下所有元素,一个很自然的改进就是使用多台机器。假设有hash(elem)%8==0
的元素,第hash(elem)%8==1
的元素,以此类推。查询的时候,先计算这个元素在哪台机器上,然后去那台机器上的
方案
如果允许近似计算,那么有很多高效的近似算法,单机就可以处理海量的数据。下面讲几个经典的近似算法。
方案3: Count-Min Sketch
- 选定
d 个hash 函数,开一个dxm 的二维整数数组作为哈希表 - 对于每个元素,分别使用
d 个hash 函数计算相应的哈希值,并对m 取余,然后在对应的位置上增1 ,二维数组中的每个整数称为sketch - 要查询某个元素的频率时,只需要取出
d 个sketch, 返回最小的那一个(其实d 个sketch 都是该元素的近似频率,返回任意一个都可以,该算法选择最小的那个)

这个方法的思路和
- 空间复杂度
O(dm)
。Count-Min Sketch 需要开一个dxm
大小的二位数组,所以空间复杂度是O(dm)
- 时间复杂度
O(n)
。Count-Min Sketch 只需要一遍扫描,所以时间复杂度是O(n)
方案4: Count-Mean-Min Sketch
- 来了一个查询,按照
Count-Min Sketch 的正常流程,取出它的d 个sketch - 对于每个
hash 函数,估算出一个噪音,噪音等于该行所有整数( 除了被查询的这个元素) 的平均值 - 用该行的
sketch 减去该行的噪音,作为真正的sketch - 返回
d 个sketch 的中位数
class CountMeanMinSketch {
// initialization and addition procedures as in CountMinSketch
// n is total number of added elements
long estimateFrequency(value) {
long e[] = new long[d]
for(i = 0; i < d; i++) {
sketchCounter = estimators[i][ hash(value, i) ]
noiseEstimation = (n - sketchCounter) / (m - 1)
e[i] = sketchCounter – noiseEstimator
}
return median(e)
}
}