Redis-布隆过滤器BloomFilter
- 由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素
- 减少内存占用,不保存数据信息,只是在内存中做一个是否存在的标记flag
- 布隆过滤器是一种类似set的数据结构只是统计结果在巨量数据下有点小瑕疵,不够完美
主要作用
- 高效的插入和查询,占用空间小,返回的结果是不确定性和不完美
- 在做元素判断是否存在时,若返回结果为存在,则元素不一定真的存在,若返回结果为不存在时,则是真的不存在
- 布隆过滤器可以添加元素,但是不能删除元素由于涉及hashcode判断依据,删掉元素会导致误判率增加
原理说明
1. 添加key时
- 使用多个hash函数对key进行hash运算得到一个整数索引值,对位数组长度进行取模运算得到一个位置
- 每个hash函数都会得到一个不同的位置,将这几个位置都置1就完成了add操作
2. 查询key时
- 只要有其中一位是零就表示这个key不存在,但如果都是1,则不一定存在对应的key
3. 哈希冲突导致数据查询不精准
- 映射函数本身就是散列函数,散列函数是会有碰撞的。(见图3号坑两个对象都1)
- 散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的,但也可能不同,这种情况称为“散列碰撞(collision)”
4. 为什么不能删除
- 布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的, 因此误判的根源在于相同的 bit 位被多次映射且置 1
- 这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位。 如果我们直接删除这一位的话,会影响其他的元素
扩容说明
- 使用时最好不要让实际元素数量远大于初始化数量,一次给够避免扩容
- 当实际元素数量超过初始化数量时,应该对布隆过滤器进行重建重新分配一个 size 更大的过滤器,再将所有的历史元素批量 add 进行
使用场景
1. 解决缓存穿透问题
- 把已存在数据的key存在布隆过滤器中,相当于redis前面挡着一个布隆过滤器。
- 当有新的请求时,先到布隆过滤器中查询是否存在:如果布隆过滤器中不存在该条数据则直接返回;
- 如果布隆过滤器中已存在,才去查询缓存redis,如果redis里没查询到则再查询Mysql数据库
2. 黑名单校验,识别垃圾邮件
- 把所有黑名单都放在布隆过滤器中,在收到邮件时,判断邮件地址是否在布隆过滤器中即可
优点
- 高效地插入和查询,内存占用bit空间少
缺点
- 不能删除元素。因为删掉元素会导致误判率增加,因为hash冲突同一个位置可能存的东西是多个共有的,删除一个元素的同时可能也把其它的删除了。
- 存在误判,不能精准过滤