现有50亿个电话号码,现有10万个电话号码,如何要快速准确的判断这些电话号码是否已经存在?
-
布隆过滤器是一种类似set的数据结构,只是不太准确,
当判断元素是否存在时返回结果存在但真实不一定存在
;当返回不存在时肯定是不存在
,所以判断去重时有一定的误判概率。 -
当然,误判只会发生在过滤器没有添加过的元素,对于添加过的元素不会发生误判。
-
特点:高效地插入和查询,占用空间少,返回的结果是不确定性的。
Redis布隆过滤器的基本使用
在Redis
中,布隆过滤器有两个基本命令,分别是:
bf.add
:添加元素到布隆过滤器中,类似于集合的sadd
命令,不过bf.add
命令只能一次添加一个元素,如果想一次添加多个元素,可以使用bf.madd
命令。bf.exists
:判断某个元素是否在过滤器中,类似于集合的sismember
命令,不过bf.exists
命令只能一次查询一个元素,如果想一次查询多个元素,可以使用bf.mexists
命令。
布隆过滤器的高级使用
上面的例子中使用的布隆过滤器只是默认参数的布隆过滤器,它在我们第一次使用 bf.add 命令时自动创建的。Redis
还提供了自定义参数的布隆过滤器,想要尽量减少布隆过滤器的误判,就要设置合理的参数。
在使用 bf.add
命令添加元素之前,使用 bf.reserve
命令创建一个自定义的布隆过滤器。bf.reserve
命令有三个参数,分别是:
key
:键error_rate
:期望错误率,期望错误率越低,需要的空间就越大。capacity
:初始容量,当实际元素的数量超过这个初始化容量时,误判率上升。
比如:
如果对应的key
已经存在时,在执行bf.reserve
命令就会报错。如果不使用bf.reserve
命令创建,而是使用Redis
自动创建的布隆过滤器,默认的error_rate
是0.01
,capacity是 100
。
布隆过滤器的 error_rate
越小,需要的存储空间就越大,对于不需要过于精确的场景,error_rate
设置稍大一点也可以。布隆过滤器的capacity
设置的过大,会浪费存储空间,设置的过小,就会影响准确率,所以在使用之前一定要尽可能地精确估计好元素数量,还需要加上一定的冗余空间以避免实际元素可能会意外高出设置值很多。总之,error_rate
和 capacity
都需要设置一个合适的数值。
布隆过滤器的应用
- 解决缓存穿透的问题
一般情况下,先查询缓存是否有该条数据,缓存中没有时,再查询数据库。当数据库也不存在该条数据时,每次查询都要访问数据库,这就是缓存穿透。缓存穿透带来的问题是,当有大量请求查询数据库不存在的数据时,就会给数据库带来压力,甚至会拖垮数据库。
可以使用布隆过滤器解决缓存穿透的问题,把已存在数据的key
存在布隆过滤器中。当有新的请求时,先到布隆过滤器中查询是否存在,如果不存在该条数据直接返回;如果存在该条数据再查询缓存查询数据库。
- 黑名单校验
发现存在黑名单中的,就执行特定操作。比如:识别垃圾邮件,只要是邮箱在黑名单中的邮件,就识别为垃圾邮件。假设黑名单的数量是数以亿计的,存放起来就是非常耗费存储空间的,布隆过滤器则是一个较好的解决方案。把所有黑名单都放在布隆过滤器中,再收到邮件时,判断邮件地址是否在布隆过滤器中即可。