布隆过滤器

2022-09-06  本文已影响0人  shark没有辣椒

布隆过滤器(Bloom Filter)是由 Bloom 于 1970 年提出的。我们可以把它看作由位数组和一系列哈希函数两部分组成的数据结构。相比于我们平时常用的的 List、Map 、Set 等数据结构,它占用空间更少并且效率更高,但是缺点是其返回的结果是概率性的,而不是非常准确的。理论情况下添加到集合中的元素越多,误报的可能性就越大。并且,存放在布隆过滤器的数据不容易删除。

图1

位数组中的每个元素都只占用 1 bit ,并且每个元素只能是 0 或者 1。这样申请一个 1000w 个元素的位数组只占用 10000000Bit / 8 = 1250000 Byte / 1024 ≈ 1222kb / 1024 ≈ 1M 的空间。

原理介绍

当一个元素加入布隆过滤器中的时候,会进行如下操作:

当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行如下操作:

因为不同的字符串可能哈希出来的位置相同(就是我们常说的哈希冲突),所以布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。

使用场景

一般在亿级以上数据判断给定数据是否存在的场景,推荐使用布隆过滤器,比如避免缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)、垃圾邮件地址过滤、浏览器检查钓鱼网站等。

开源实现

在实际项目中我们一般不需要手动实现布隆过滤器,比如Guava 中布隆过滤器的实现就很权威。

Guava布隆过滤器

guava提供了一套很方便使用布隆过滤器的方法,下面我们创建了一个最多存放 1500 个整数的布隆过滤器,并且我们可以容忍误判的概率为百分之0.01

// 创建布隆过滤器对象
BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(),  1500, 0.01);
// 判断指定元素是否存在
System.out.println(filter.mightContain(1));
System.out.println(filter.mightContain(2));
// 将元素添加进布隆过滤器
filter.put(1);
filter.put(2);
System.out.println(filter.mightContain(1));
System.out.println(filter.mightContain(2));

Guava 提供的布隆过滤器的实现还是很不错的(想要详细了解的可以看一下它的源码实现,大致是采用了murmur3_128哈希算法求得hash值,然后对长度进行求余得到数组hash值),但是它有一个重大的缺陷就是只能单机使用(另外,容量扩展也不容易),而现在互联网一般都是分布式的场景。为了解决这个问题,我们就需要用到 Redis 中的布隆过滤器了。

Redis布隆过滤器

Redis v4.0 之后有了 Module(模块/插件) 功能,Redis Modules 让 Redis 可以使用外部模块扩展其功能 。布隆过滤器就是其中的 Module。详情可以查看 Redis 官方对 Redis Modules 的介绍 :redis.io/modules
RedisBloom 提供了多种语言的客户端支持,包括:Python、Java、JavaScript 和 PHP。

常用命令

另外, BF. RESERVE 命令需要单独介绍一下:

这个命令的格式如下:

下面简单介绍一下每个参数的具体含义:

总结


本文引用自https://zhuanlan.zhihu.com/p/433689454

上一篇 下一篇

猜你喜欢

热点阅读