去重小结
最近在做爬虫的时候,遇到了去重的问题,关于去重,有很多地方可以做,比如
- 内存级别,利用 hashmap,准确,性能好但是内存有限
- 数据库,利用唯一键,准确,存储量大但是性能差
- 内存级别 BloomFilter,利用 bitmap,性能好,存储量比 hashmap 大得多,但是有误差
实际使用的时候要根据场景去 tradeoff,没有最好的办法,只有最合适的办法
基数统计
同样,当我们需要统计个数时,也有很多办法,比如
- 内存级别 hashset,准确,但是存储量跟数据量成正比,原始数据还存在
- 数据库也可以做,准确但性能较差
- 内存级别,Hyperloglog,只需少量内存即可,但误差较大
如果我们单单只是技术统计,对准确率要求并不高,可以采取 Hyperloglog,只不过没有记录原始数据,但这恰好为节省内存埋下了伏笔
BloomFilter 原理
有 k 个 hash 函数,对每一个 key 进行 hash 函数计算大小,将 m 位 0 字符串在对应的取余赋值为 1 即可
检查是否存在:计算 key 对应的 k 个 hash值在字符串中的位是否全为 1,如果是,则有可能存在,否则肯定不存在
例子, key = bloom hashcode = [1, 2, 3]
011100000000000000000
接下来 key = filter 经过同样的 hash 计算 hashcode = [2,4,6]
经过计算不存在,则放入
011101000000000000000
实际应用中如何选择 m,k,f 的大小,有一个数据公式推导,大家可以自行 Google
HyperLogLog 原理
使用概率的原理
这篇文章还不错 https://blog.csdn.net/firenet1/article/details/77247649
总结一下,就是说,我们丢硬币的场景,第一次出现正面,之前都是反面的概率与实验次数有一个关系 n = 2^k,那么我们将 key 映射成 二进制hashcode,0001010, 该过程完全随机,那么 n 就等于 2^4,也就是说试验次数达到 8,但误差较大,所以我们采用多个映射取平均,这样误差就会变小
但是这样的误差很大
大家可以看看 stream-lib 里边的实现,很经典
网友评论