简介
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。
优点:空间效率和查询时间都比一般的算法要好的多
缺点:有一定的误识别率和删除困难。
详细
布隆过滤器本身是一个很长的二进制向量,既然是二进制的向量,那么显而易见的,存放的不是0,就是1。
新建一个16位的布隆过滤器,如图
随机映射函数,比如我们使用4个hash算法:hash1,hash2,hash3,hash4
对于布隆过滤器本身来说,并没有存储任何数据,只是计算该数据的位置,然后存储向量值
有4个值a,b,c,d
为了便于说明,这里将二进制的向量抽象成阵列的样子(其实就是哈希表Hashtable),4个值对应的计算结果如图所示。
假设一个集合中,如果已经存储了a,b
判断c是否存在集合中?通过计算得知c不在集合中
判断d是否存在集合中?通过计算得知d“存在”集合中,但是实际上d不存在,这就是误差
为什么会存在误差呢?因为d的hash值和a,b的hash值冲突了,也叫做hash碰撞。
为了减少误差,可以增加hash函数的个数,但是相应的会降低计算的速度。
由于布隆过滤器只存储key对应的hash值,不像B树那样需要存储key,所以节约了空间,数据量巨大时效果显著
现在看下面的模型应该就很好理解了,假如一个集合中存储了x,y,z元素,判断w是否在集合中
通过计算w得知有一个hash值为0,那么说明w不在集合中
根据上面的理解,下面我们来做判断题:
在布隆过滤器中,如果判断一个值不在集合中,那么它可能不在集合中(False)
在布隆过滤器中,如果判断一个值不在集合中,那么它一定不在集合中(True)
在布隆过滤器中,如果判断一个值在集合中,那么它可能不在集合中(True)
在布隆过滤器中,如果判断一个值在集合中,那么它可能在集合中(True)
应用:
网页URL的去重,垃圾邮件的判别,集合重复元素的判别,查询加速(比如基于key-value的存储系统)、数据库防止查询击穿
有时候我们需要判断一个元素是否在一个集合中。比如,在字处理软件中,需要检查一个单词是否拼写正确(也就是要判断它是否在已知的字典里);在警察系统中,一个嫌疑人的名字是否出现在嫌疑名单上;在网络爬虫里,一个网址是否已经被访问过,等等。
实例:
1、已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
8位最多99 999 999,大概需要99m个bit,大概10几M字节的内存即可。
2、在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。
采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存232*2bit=1GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。
实现
import java.util.BitSet;
/**
* 布隆过滤器实现
*/
public class BloomFilter {
//1、二进制向量长度,2的n次幂
/**
* 一个长度为10 亿的比特位
*/
private static final int size = 1 << 30;
/**
* 初始化布隆过滤器的bitmap
*/
private static BitSet bitSet=new BitSet(size);
//2、hash算法的素数因子
/**
* 为了降低错误率,使用加法hash算法,所以定义一个8个元素的质数数组
*/
private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 63};
//3、hash函数
/**
* 相当于构建 8 个不同的hash算法
*/
private static HashFunction[] functions = new HashFunction[seeds.length];
/**
* 添加数据
* @param str 需要加入的值
*/
public static void add(String str){
if (str != null) {
for (HashFunction f : functions) {
bitSet.set(f.hash(str),true);
}
}
}
/**
* 判断值是否存在
* @param str 需要判断的值
* @return
*/
public static boolean contains(String str){
if (str == null) {
return false;
}
boolean ret=true;
for (HashFunction f : functions) {
ret=bitSet.get(f.hash(str));
//只要有一个hash函数返回false就返回
if (!ret) {
return ret;
}
}
return ret;
}
/**
* 测试
*/
public static void main(String[] args) {
//初始化hash函数
for (int i = 0; i < seeds.length; i++) {
functions[i]=new HashFunction(seeds[i],size);
}
//添加1个亿的数据
for (int i = 0; i < 100000000; i++) {
add(String.valueOf(i));
}
String id="123456789";
add(id);
System.out.println(contains(id));//true
System.out.println(contains("234567890"));//false
}
}
/**
* Hash函数
*/
class HashFunction {
//hash素数因子
private int seed;
//size是2的n次幂,这样size-1得到所有bit为1
private int size;
public HashFunction(int seed, int size) {
this.seed = seed;
this.size = size;
}
public int hash(String value) {
int result = 0;
if (value != null) {
int len = value.length();
for (int i = 0; i < len; i++) {
result = result * seed + value.charAt(i);
}
}
return result & (size - 1);
}
}
参考
百度百科:
https://baike.baidu.com/item/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8/5384697?fr=aladdin
布隆过滤器(Bloom Filter)详解:
https://www.cnblogs.com/liyulong1982/p/6013002.html
布隆过滤器(BloomFilter)的原理、实现和探究: