前言
上一篇简单介绍了布隆过滤器,还用java做了一个简单实现,这里我们介绍Redisson和Guava的实现。
本文设定的误判率逻辑:在布隆过滤器中写入test0-test100000的数据,然后校验test100000-test200000是否在布隆过滤器中,如果存在,则表示发生了误判。
Redisson实现
Redisson中布隆过滤器的实现类是RBloomFilter,不能在集群模式中使用,从源码中可以看出其依赖于RedissonBitSet来实现,具体可以参考redis中的getBit指令
RBloomFilter中包含了几个对应的方法:
//初始化布隆过滤器,var1表示大小,var3表示容错率
boolean tryInit(long var1, double var3);
//添加对象
boolean add(T var1);
//判断对象是否存在
boolean contains(T var1);
//返回预计插入数量
long getExpectedInsertions();
//返回容错率
double getFalseProbability();
//返回hash函数个数
int getHashIterations();
//对象插入后,估计插入数量
long count();
//布隆过滤器位数组的大小
long getSize();
根据设定的误判率,会自动改变集合的容量,比如代码中我们设定的误判率是0.03,集合的容量是729844;但是如果我设定误判率是0.9,那么size就会下调到21929。还有,设定的误判率和实际的误判率会有偏差,比如测试下来实际的误判率是0.07。
测试类
@Test
public void testRedissonBloom() {
int size = 100000;
RBloomFilter<Object> bloom = redissonClient.getBloomFilter("bloomKey");
bloom.tryInit(size, 0.03);
for (int i = 0; i < size; i++) {
bloom.add("test" + i);
}
float mistakeCount = 0.0f;
for (int i = size; i < size * 2; i++) {
if (bloom.contains("test" + i)) {
mistakeCount++;
}
}
log.info("test5是否存在:{}", bloom.contains("test5"));
log.info("abc是否存在:{}", bloom.contains("abc"));
log.info("误判:{},误判率:{}", mistakeCount, mistakeCount / size);
log.info("hash函数个数:{}", bloom.getHashIterations());
log.info("容错率:{}", bloom.getFalseProbability());
log.info("预计插入数量:{}", bloom.getExpectedInsertions());
log.info("插入对象数量:{}", bloom.count());
log.info("布隆过滤器位数组的大小:{}", bloom.getSize());
}
测试输出:
test5是否存在:true
abc是否存在:true
误判:7077.0,误判率:0.07077
hash函数个数:5
容错率:0.03
预计插入数量:100000
插入对象数量:98735
布隆过滤器位数组的大小:729844
Guava实现
Guava中的布隆过滤器还是一个beta版本
从实际的误判率来看,Guava的版本比Redisson要靠谱很多。设定误判率0.01,实际误判率0.0102。
public static void main(String[] args) {
int size = 100000;
double fpp = 0.01d;
BloomFilter<String> bloomFilter = BloomFilter.create(
Funnels.stringFunnel(Charset.defaultCharset()), size, fpp);
for (int i = 0; i < size; i++) {
bloomFilter.put("test" + i);
}
int mistakeCount = 0;
for (int i = size; i < size * 2; i++) {
if (bloomFilter.mightContain("test" + i)) {
mistakeCount++;
}
}
long approximateElementCount = bloomFilter.approximateElementCount();
System.out.println("元素数量[大约]:"+approximateElementCount);
double expectedFpp = bloomFilter.expectedFpp();
System.out.println("设定的误判率:"+expectedFpp);
System.out.println("误判数量:" + mistakeCount);
System.out.println("误判率:" + (mistakeCount* 1.0 / size ));
}
测试输出
元素数量[大约]:100013
设定的误判率:0.010044335605248233
误判数量:1020
误判率:0.0102