一、引言
在处理大量数据的场景中,我们经常会遇到判断一个元素是否在某个集合中的问题。传统的方法可能是使用 HashMap 等集合将数据保存起来,然后进行比较确定,但在元素很多的情况下,这种方式会非常浪费空间,检索速度也会越来越慢。这时,布隆过滤器(Bloom Filter)应运而生。本文将详细介绍布隆过滤器的原理、使用场景以及优缺点。
二、什么是布隆过滤器
布隆过滤器是 1970 年由布隆提出的,它实际上是一个很长的二进制向量和一系列随机映射函数组成,主要用于判断一个元素是否在一个集合中。它不存储数据本身,仅存储哈希结果取模运算后的位标记,因此占用内存小,适合海量数据场景。其优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
三、布隆过滤器的原理
数据结构
布隆过滤器是由很长的二进制向量(即可以理解成很长的 0、1 数组)与一系列随机映射函数(Hash 函数)构成。由于其数据结构仅需要存储 “0” 或 “1”,因此所占用内存极少。
检索和插入原理
Hash 函数简介:Hash 函数就是把输入值通过特定方式处理后生成一个值,这个值等同于存放数据的地址。
插入数据原理:
当一个元素加入布隆过滤器中的时候,会进行如下操作:
使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(有几个哈希函数得到几个哈希值)
根据得到的哈希值,在位数组中把对应下标的值置为 1
如下图所示:
检索数据原理:将待检索元素通过同样的一系列 Hash 函数得到对应的一系列数组地址(索引下标),判断这几个索引下标对应的值是否均为 1,是的话则说明存在,否则不存在。
对给定元素再次进行相同的哈希计算
得到哈希值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值存在布隆过滤器当中,如果存在一个值不为 1,说明该元素不在布隆过滤器中
例如我们查询 “你好” 这个值是否存在,哈希函数返回了 3、5、7三个值
如下图所示:
结果得到三个 1 ,说明 “你好” 是有可能存在的。
元素的删除
布隆过滤器对元素的删除不太支持,因为不同的值可能经过一系列 Hash 函数后得到的一系列地址,总有可能两个或多个值经过某个 Hash 函数映射后得到其中一个地址会一样,此时数组中对应的下标肯定为 1。
当删除或修改某个元素后,如果将其原来对应地址的值从 1 改为 0,无法确定这个地址是否也对应其他值,可能会导致其他原本存在的值在检索时返回不存在的情况。
四、布隆过滤器的使用场景
区块链中使用布隆过滤器来加快钱包同步;
数据库防止穿库,Google Bigtable,HBase 和 Cassandra 以及 Postgresql 使用BloomFilter来减少不存在的行或列的磁盘查找。避免代价高昂的磁盘查找会大大提高数据库查询操作的性能
判断用户是否阅读过某一个视频或者文章,类似抖音,刷过的视频往下滑动不再刷到,可能会导致一定的误判,但不会让用户看到重复的内容
网页爬虫对URL去重,采用布隆过滤器来对已经爬取过的URL进行存储,这样在进行下一次爬取的时候就可以判断出这个URL是否爬取过了
使用布隆过滤器来做黑名单过滤,针对不同的用户是否存入白名单或者黑名单,虽然有一定的误判,但是在一定程度上还是很好的解决问题
缓存击穿场景,一般判断用户是否在缓存中,如果存在则直接返回结果,不存在则查询数据库,如果来一波冷数据,会导致缓存大量击穿,造成雪崩效应,这时候可以用布隆过滤器当缓存的索引,只有在布隆过滤器中,才去查询缓存,如果没查询到则穿透到数据库查询。如果不在布隆过滤器中,则直接返回,会造成一定程度的误判
WEB拦截器,如果相同请求则拦截,防止重复被攻击。用户第一次请求,将请求参数放入布隆过滤器中,当第二次请求时,先判断请求参数是否被布隆过滤器命中。可以提高缓存命中率。Squid 网页代理缓存服务器在 cache digests 中就使用了布隆过滤器。Google Chrome浏览器使用了布隆过滤器加速安全浏览服务
Google 著名的分布式数据库 Bigtable 使用了布隆过滤器来查找不存在的行或列,以减少磁盘查找的IO次数
Squid 网页代理缓存服务器在 cache digests 中使用了也布隆过滤器
Venti 文档存储系统也采用布隆过滤器来检测先前存储的数据
SPIN 模型检测器也使用布隆过滤器在大规模验证问题时跟踪可达状态空间
Google Chrome浏览器使用了布隆过滤器加速安全浏览服务
五、布隆过滤器的优缺点
-
优点
- 时间复杂度低,增加和查询元素的时间复杂为 O (N),(N 为哈希函数的个数,通常情况比较小)。
- 保密性强,不存储元素本身。
- 存储空间小,如果允许存在一定的误判,布隆过滤器是非常节省空间的(相比其他数据结构如 Set、Map 集合)。
-
缺点
- 有一定的误判率,但是可以通过调整参数来降低。
- 无法获取元素本身。
- 很难删除元素。
布隆过滤器中一个元素如果判断结果为存在的时候元素不一定存在,但是判断结果为不存在的时候则一定不存在。因此,布隆过滤器不适合那些对结果必须精准的应用场景。
六、总结
布隆过滤器是一种非常实用的数据结构,在处理大规模数据时,能够以较小的内存占用和快速的查询速度判断元素的存在性。虽然存在一定的误判率和删除困难等缺点,但在很多场景下,只要允许一定的误判率,布隆过滤器都是一个非常好的选择。在实际应用中,可以根据具体需求选择合适的实现方式,如 Redis 中的布隆过滤器,以满足不同场景下的需求。
参考连接
一篇吃透布隆过滤器(Bloom Filter)及其使用场景-CSDN博客
Redis-布隆过滤器(Bloom Filter)详解-CSDN博客