布隆过滤器
BloomFilter概念及原理
布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。主要用于判断一个元素是否在一个集合中。
布隆过滤器的原理是,当⼀个元素被加⼊集合时,通过K个散列函数将这个元素映射成⼀个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(⼤约)知道集合中有没有它了:如果这些点有任何⼀个0,则被检元素⼀定不在;如果都是1,则被检元素很可能在。 如下图所示:
比如:我们现在把元素 A、B、C加载到布隆过滤器中,每个元素经过3个散列函数映射到不同的位置,并将该位置置为1,如果我们判断元素D、发现它映射之后的位置都是1,但是我们不能判断元素D一定存在,因为该位置的1并不是由元素D置为的1,这就是布隆过滤器的误判,是由于哈希冲突造成的,反之我们看元素E,它映射之后有一个位置是0,那么说明元素E一定不存在,这就是布隆过滤器的基本原理。
总结来说就是下面两句话:
- 如果元素映射之后的位置有任何一个是0,那么该元素一定不存在
- 如果都是1,则该元素可能存在
上面说的是布隆过滤器的添加和查询操作,那如果我们想删除一个元素呢?
由于布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位,如果我们直接删除这一位的话,就会影响到其他的元素。
布隆过滤器的优点:
相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数O(K)级别的,其次,布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势。
布隆过滤器的缺点:
存在误判,可能该元素并不存在,但是该元素映射之后的所有位都是1。再就是删除元素困难,可能会影响其他的元素。
布隆过滤器的使用场景及实现
布隆过滤器的典型应用有:
- 缓存穿透问题,过滤掉不存在的数据,阻止请求打到数据库上使数据库宕机。
- WEB拦截器,如果相同请求则拦截,防止重复被攻击。
- …
自定义一个 BloomFilter
public class MyBloomFilter {
// 一个长度为10 亿的比特位
private static final int DEFAULT_SIZE = 256 << 22;
// 为了降低错误率,使用加法hash算法,所以定义一个8个元素的质数数组
private static final int[] seeds = {
3, 5, 7, 11, 13, 31, 37, 61};
// 相当于构建 8 个不同的hash算法
private static HashFunction[] functions = new HashFunction[seeds.length];
// 初始化布隆过滤器的 bitmap
private static BitSet bitset = new BitSet(DEFAULT_SIZE);
/**
* 添加数据
* @param value 需要加入的值
*/
public static void add(