手撕布隆过滤器,真香!

 作者 | 杜如东

要想学会递归,首先学会递归

一、问题背景

不安全网页的黑名单包含 100 亿个黑名单网页,每个网页的 URL 最多占用 64 字节。现在想要实现一种网页过滤系统,可以根据网页的 URL 判断该网站是否在黑名单上,请设计该系统。要求该系统允许有万分之一以下的判断失误率,并且使用的额外空间不要超过 30G。

通常我们判断一个 URL 存在与否,可能会用 HashMap,查询效率极高,时间复杂度 O(1),但是其占用的内存空间就没那么美丽了。那么有没有一种数据结构,查询速度快、占用空间又小呢?废话,当然是存在的,它就是我们今天的主角:Bloom 过滤器

二、 什么是Bloom 过滤器
1、基本思想

Bloom 过滤器是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点,把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在。这就是布隆过滤器的基本思想。

Bloom 过滤器其实和 HashMap 有点类似,他们都需要利用哈希函数求得输入元素的哈希值,然后对数组长度取模,只不过 Bloom 过滤器需要多个哈希函数,占用空间更小。Bloom 过滤器其实就是一个概率型的数据结构,它会告诉你,一个元素可能存在或者一定不存在

2、举个栗子
1、插入和查询操作

2、删除操作

标准的 Bloom 过滤器并不支持删除操作,一个元素通过 k 个哈希函数映射到 bit 数组中的 k 个点,如果删除的时候,直接将这 k 个点置为 0,会影响其他元素的判断,Counting Bloom filter 可以解决这类问题,具体可以参考Counting Bloom Filter 的原理和实现。


三、如何确定散列函数的个数和bit数组的长度

根据上图可知,如果 bit 数组的长度不变,随着集合元素越来越多,bit 数组中的所有 bit 将均置为 1,任何输入元素都会被认为可能存在,误差率将越来越高。那么如何确定散列函数的个数和 bit 数组的长度呢,接下来咱们进行简单的数学推导。

如果一个随机试验所包含的单位事件是有限的,且每个单位事件发生的可能性均相等,则这个随机试验叫做拉普拉斯试验,这种条件下的概率模型就叫古典概型。

假设存在一个长度为 m 的 bit 数组,k 个散列函数,n 个待插入的元素。

设误差率为 p ,设 i 为 bit 数组中的任意一个位置。

1、误差率推导

1. 根据古典概型,我们可以假设存在一个完美的散列函数(即一个待插入元素能等概率的映射到 bit 数组中的某一个位置)。那么 bit[i] 被置为 1 的概率为   ,反之,不被置为 1 的可能性为   。

2. 那么经过 k 次散列函数后,bit[i] 为 0 的概率是   。

3. 那么在 n 个元素完全插入后,bit[i]为 0 的概率为   ,置为 1 的概率为   。

4. 那么出现误判(一个元素通过散列函数映射后 k 个位置都为 1)的概率是   。

5. 根据极限定理   ,   。

2、散列函数个数推导

令   ,得到   ,我们需要求的便是   的最小值。

可以很明显的看出,在待输入元素 (n) 个数固定的情况下,随着 bit 数组长 (m) 度越来越大,误差率越来越小。

3、空间大小推导


四、如何在 Redis 中使用 Bloom 过滤器

在 Redis 中,Bloom 过滤器存在几个基本命令,分别是:

  • bf.add : 添加元素到 Bloom 过滤器中

  • bf.madd : 批量添加元素到 Blomm 过滤器中

  • bf.exists : 查询某个元素是否在 Bloom 过滤器中

  • bf.mexists : 批量查询某些元素是否在 Bloom 过滤器中

我们第一次使用 bf.add 命令时,会自动创建一个默认参数的 Bloom 过滤器,如果想创建自定义参数的 Bloom 过滤器,我们需要在使用 bf.add 命令添加元素之前,使用 bf.reserve 命令创建一个自定义的 Bloom 过滤器,该命令有三个参数,分别是:

  • key : 键

  • error_rate :误判率 (p)

  • capacity :初始容量,当输入元素集合大小 (n) 大于该数值时,误判率会上升

设置了 error_rate 和 capacity,redis 底层通过公式   ,可以轻易的算出 bit 数组的长度,有兴趣的童鞋可以尝试算一下。

例如:

 bf.reverse filter 0.0001 10000000000

看到这里,可以回头去看本文最初的问题,聪明的你,心里应该已经有答案了。

五、总结
1、优点
  • Bloom 过滤器本质上是一个概率型数据结构,它可以告诉你一个元素可能存在或者肯定不存在

  • 插入和查询效率高

2、缺点
  • 具有一定误判率

  • 标准 Bloom 过滤器不支持删除操作

全文完


以下文章您可能也会感兴趣:

我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值