google guava bloom filter包的坑

来源:互联网 发布:农业部渔船数据科 编辑:程序博客网 时间:2024/06/06 04:41

关于bloom filter以及原理,见我之前转的这篇:

http://blog.csdn.net/inte_sleeper/article/details/7824857


下面开始实战篇。google guava包是包含了一个bloom filter的实现的,使用方式比较简单,其实就是一行代码:

BloomFilter<CharSequence> filter = BloomFilter.create(Funnels.stringFunnel(), 10000000, 0.001F);

上面的代码创建了一个以string为key的bloom filter,预期的插入量是1KW,错误率是0.1%。

查询的时候,直接调 filter.mightContain()方法就可以,非常简单。


下面开始说坑吧。guava的BloomFilter,内部的一段实现代码如下:

public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions,      double falsePositiveProbability) {    checkNotNull(funnel);    checkArgument(expectedInsertions >= 0, "Expected insertions cannot be negative");    checkArgument(falsePositiveProbability > 0.0 & falsePositiveProbability < 1.0,        "False positive probability in (0.0, 1.0)");    if (expectedInsertions == 0) {      expectedInsertions = 1;    }    int numBits = optimalNumOfBits(expectedInsertions, falsePositiveProbability);    int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);    return new BloomFilter<T>(new BitArray(numBits), numHashFunctions, funnel,        BloomFilterStrategies.MURMUR128_MITZ_32);}

它会根据预期的插入量以及错误率,计算出numBits,即需要的位数。然后使用BitArray创建出numBits的数据位,BitArray的最大size=int.MAX_VALUE(约21亿)。

然后根据预期插入量以及计算出的numBits计算出最优的哈希函数个数。其实这里并不能说是最优,只是根据这两个参数做出的一种平衡。

这时候,千万别认为你可以将预期插入量设为21亿。事实上,你可以尝试一下,将预期插入量这个参数值从2亿慢慢增加至10亿,你会发现,内存占用都是一样的(试验前,请先调整JVM的-Xmx参数)。接下来我们看看在不同的参数条件下,numBits值以及numHashFunctions值的变化:

expectedInsertionsfalsePositiveProbabilitynumBitsnumHashFunctions6KW0.00011150207005131亿0.00011917011675132亿0.0001214748364775亿0.000121474836473从上面的表格可以看到,在0.0001的错误率下,插入量不到1.5亿的时候,numBits已经到达了BitArray的最大容量了,这时如果再增加插入量,哈希函数个数就开始退化。

到5亿的时候,哈希函数个数退化到了只有3个,也就是说,对每一个key,只有3位来标识,这时准确率就会大大下降。

这时有两种解决方案:

第一种当然就是减少预期插入量,1亿以内,还是可以保证理论上的准确率的。

第二种,如果你的系统很大,就是会有上亿的key,这时可以考虑拆分,将一个大的bloom filter拆分成几十个小的(比如32或64个),每个最多可以容纳1亿,这时整体就能容纳32或64亿的key了。查询的时候,先对key计算一次哈希,然后取模,查找特定的bloom filter即可。

原创粉丝点击