我正在参加「掘金·启航计划」
一、介绍
布隆过滤器(Bloom Filter)是 1970 年由布隆提出的,主要用于判断一个元素是否在一个集合中。它实际上是一个很长的二进制向量和一系列随机映射函数,因此空间效率和查询时间都非常高,缺点是有一定的误判率和删除困难。适用于一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。
二、原理
Bloom Filter 是由一个固定大小的二进制向量或者位图(bitmap)和一系列映射函数组成的。
在初始状态时,对于长度为 m 的位数组,它的所有位都被置为0,如下图所示:
当有变量被加入集合时,通过 K 个映射函数将这个变量映射成位图中的 K 个点,把它们置为 1(假定有两个变量都通过 3 个映射函数)。
查询某个变量的时候我们只要看看这些点是不是都是 1 就可以大概率知道集合中有没有它了
- 如果这些点有任何一个 0,则被查询变量一定不在;
- 如果都是 1,则被查询变量很可能存在
为什么是可能存在,而不是一定存在呢?这是由于散列函数会发出碰撞。如下图所示,即使集合中仅包含元素e1、e3、e4,Bloom Filter 同样会认为 e2 存在于集合中。因此可以发现,Bloom Filter 存在假正例(FP),不存在假负例(FN)
三、处理步骤
1. 添加元素
- 用 k 个哈希函数处理元素
- 得到元素在位数组上的 k 个位置
- 将这 k 个位置置为 1
2. 查找元素
- 用 k 个哈希函数处理要查找的元素
- 得到元素在位数组上的 k 个位置
- 如果 k 个位置有一个为 0,则肯定不在集合中
- 如果 k 个位置全部为 1,则可能在集合中
四、优缺点
由 Bloom Filter 的原理以及操作步骤可以得知,Bloom Filter 的优点和缺点都非常明显
优点
- 相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间复杂度为 O(k);
- 哈希函数之间相互没有关系,便于并行操作;
- 布隆过滤器不需要存储元素本身。
缺点
- 存在误判,且随着存入的元素数量增加,误算率随之增加;
- 一般情况下不能进行删除元素的操作,使用计数布隆过滤器(Counting Bloom Filter)可以一定程度上解决这个问题;
五、使用场景
布隆过滤器可用于网页 URL 去重、垃圾邮件识别、大集合中重复元素的判断和缓存穿透等问题。
其典型应用有:
- 业务场景中判断用户是否阅读过某视频或文章,比如抖音或头条,当然会导致一定的误判,但不会让用户看到重复的内容。
- 缓存宕机、缓存击穿场景,一般判断用户是否在缓存中,如果在则直接返回结果,不在则查询db,如果来一波冷数据,会导致缓存大量击穿,造成雪崩效应,这时候可以用布隆过滤器当缓存的索引,只有在布隆过滤器中,才去查询缓存,如果没查询到,则穿透到db。如果不在布隆器中,则直接返回。
六、最后
对于 Bloom Filter 的详细介绍以及误判率等的证明方法可见 en.wikipedia.org/wiki/Bloom_…