布隆过滤器

        之前在Redis缓存穿透的文章中提到过布隆过滤器,今天本文就详细讲一下布隆过滤器。

一、简介

        布隆过滤器实际上是一个很长的二进制数组+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中。

布隆过滤器_第1张图片

二、 基本原理:

        布隆过滤器(Bloom Filter) 实质就是一个大型位数组和几个不同的无偏hash函数(无偏表示分布均匀)。由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断某个数据是否存在。

  • 1. 初始化

布隆过滤器 本质上 是由长度为 m 的位向量或位列表(仅包含 0 或 1 位值的列表)组成,最初所有的值均设置为 0

       布隆过滤器_第2张图片

  • 2. 添加操作

当我们向布隆过滤器中添加数据时,为了尽量地址不冲突,会使用多个 hash 函数对 key 进行运算,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。
例如,我们添加一个字符串helloword
布隆过滤器_第3张图片

  • 3. 判断是否存在
  1. 向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算,查看对应的位置是否都为 1。
  2. 只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在;
  3. 如果这几个位置全都是 1,那么说明极有可能存在;

因为这些位置的 1 可能是因为其他的 key 存在导致的,也就是前面说过的hash冲突。。。。。
 
        比如我们在 add 了字符串helloword数据之后,很明显下面1/3/5 这几个位置的 1 是因为第一次添加的helloword而导致的;
        此时我们查询一个没添加过的不存在的字符串hellojava,它有可能计算后索引值也是1/3/5 ,这就是误判了......

        布隆过滤器的删除

        布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的,因此误判的根源在于相同的 bit 位被多次映射且置 1。
         这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位。如果我们直接删除这一位的话,会影响其他的元素


三、优势与局限性:

优势:

  • 高效地插入和查询,占用空间少

局限性:

  • 不能删除元素。因为删掉元素会导致误判率增加,因为hash冲突同一个位置可能存的东西是多个共有的,你删除一个元素的同时可能也把其它的删除了。
  • 存在误判,不同的数据可能出来相同的hash值

四、实际应用:

  • 缓存穿透

        使用布隆过滤器防止大量恶意请求去请求不存在的数据导致缓存穿透。

  • 黑名单校验

        发现存在黑名单中的,就执行特定操作。比如:识别垃圾邮件,只要是邮箱在黑名单中的邮件,就识别为垃圾邮件。
         假设黑名单的数量是数以亿计的,存放起来就是非常耗费存储空间的,布隆过滤器则是一个较好的解决方案。
        把所有黑名单都放在布隆过滤器中,在收到邮件时,判断邮件地址是否在布隆过滤器中即可。

五、总结:

  • 在使用布隆过滤器时最好不要让实际元素数量远大于初始化数量
  • 当实际元素数量超过初始化数量时,应该对布隆过滤器进行重建,重新分配一个 size 更大的过滤器,再将所有的历史元素批量 add 进行
  • 判断是否存在时:有,是很可能有;无,是肯定无。

你可能感兴趣的:(哈希算法,算法)