大白话布隆过滤器
Posted 博客园
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大白话布隆过滤器相关的知识,希望对你有一定的参考价值。
布隆过滤器的应用
缓存穿透
虽然有很多办法都可以解决这问题,但是我们的主角是“布隆过滤器”,没错,“布隆过滤器”就可以解决(缓解)缓存穿透问题。 至于为什么说是“缓解”,看下去你就明白了。
大量数据,判断给定的是否在其中
什么是布隆过滤器
现在需要添加一个数据:
我们通过某种计算方式,比如Hash1,计算出了Hash1(数据)=5,我们就把下标为5的格子改成1,就像下面这样:
我们又通过某种计算方式,比如Hash2,计算出了Hash2(数据)=9,我们就把下标为9的格子改成1,就像下面这样:
还是通过某种计算方式,比如Hash3,计算出了Hash3(数据)=2,我们就把下标为2的格子改成1,就像下面这样:
相信经过我这么一介绍,大家对布隆过滤器应该有一个浅显的认识了,至少你应该清楚布隆过滤器的优缺点了:
-
优点 : 由于存放的不是完整的数据,所以占用的内存很少,而且新增,查询速度够快; -
缺点 : 随着数据的增加,误判率随之增加; 无法做到删除数据; 只能判断数据是否一定不存在,而无法判断数据是否一定存在。
guava实现布隆过滤器
首先在pom引入“礼物”:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
private static int size = 1000000;//预计要插入多少数据
private static double fpp = 0.01;//期望的误判率
private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);
public static void main(String[] args) {
//插入数据
for (int i = 0; i < 1000000; i++) {
bloomFilter.put(i);
}
int count = 0;
for (int i = 1000000; i < 2000000; i++) {
if (bloomFilter.mightContain(i)) {
count++;
System.out.println(i + "误判了");
}
}
System.out.println("总共的误判数:" + count);
}
代码简单分析:
我向布隆过滤器插入了0-1000000,然后用1000000-2000000来测试误判率。
运行结果:
1999501误判了
1999567误判了
1999640误判了
1999697误判了
1999827误判了
1999942误判了
总共的误判数:10314
现在总共有100万数据是不存在的,误判了10314次,我们计算下误判率
和我们定义的期望误判率0.01相差无几。
redis实现布隆过滤器
要用redis来实现布隆过滤器,我们需要自己设计映射函数,自己度量二进制向量的长度,这对我来说,无疑是一个不可能完成的任务,只能借助搜索引擎,下面直接放出代码把。
public class RedisMain {
static final int expectedInsertions = 100;//要插入多少数据
static final double fpp = 0.01;//期望的误判率
//bit数组长度
private static long numBits;
//hash函数数量
private static int numHashFunctions;
static {
numBits = optimalNumOfBits(expectedInsertions, fpp);
numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);
}
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.0.109", 6379);
for (int i = 0; i < 100; i++) {
long[] indexs = getIndexs(String.valueOf(i));
for (long index : indexs) {
jedis.setbit("codebear:bloom", index, true);
}
}
for (int i = 0; i < 100; i++) {
long[] indexs = getIndexs(String.valueOf(i));
for (long index : indexs) {
Boolean isContain = jedis.getbit("codebear:bloom", index);
if (!isContain) {
System.out.println(i + "肯定没有重复");
}
}
System.out.println(i + "可能重复");
}
}
/**
* 根据key获取bitmap下标
*/
private static long[] getIndexs(String key) {
long hash1 = hash(key);
long hash2 = hash1 >>> 16;
long[] result = new long[numHashFunctions];
for (int i = 0; i < numHashFunctions; i++) {
long combinedHash = hash1 + i * hash2;
if (combinedHash < 0) {
combinedHash = ~combinedHash;
}
result[i] = combinedHash % numBits;
}
return result;
}
private static long hash(String key) {
Charset charset = Charset.forName("UTF-8");
return Hashing.murmur3_128().hashObject(key, Funnels.stringFunnel(charset)).asLong();
}
//计算hash函数个数
private static int optimalNumOfHashFunctions(long n, long m) {
return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
}
//计算bit数组长度
private static long optimalNumOfBits(long n, double p) {
if (p == 0) {
p = Double.MIN_VALUE;
}
return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
}
}
88可能重复
89可能重复
90可能重复
91可能重复
92可能重复
93可能重复
94可能重复
95可能重复
96可能重复
97可能重复
98可能重复
99可能重复
cnblogs.com/CodeBear/p/10911177.html
以上是关于大白话布隆过滤器的主要内容,如果未能解决你的问题,请参考以下文章
BloomFilter怎么用?使用布隆过滤器来判断key是否存在?