目录
背景
推荐工程业务中存在“过滤”的场景。例如从召回源获取到的数据需要过滤掉曝光过、点击过的数据,即判断一个数据是否在曝光、点击的集合中。
一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路,存储位置要么是磁盘,要么是内存。很多时候要么是以时间换空间,要么是以空间换时间。
在响应时间要求比较严格的情况下,如果我们存在内存里,那么随着集合中元素的增加,我们需要的存储空间越来越大,以及检索的时间越来越长,导致内存开销太大、时间效率变低。
此时需要考虑解决的问题就是,在数据量比较大的情况下,既满足时间要求,又满足空间的要求。即我们需要一个时间和空间消耗都比较小的数据结构和算法。Bloom Filter就是一种解决方案。
bloom简介
Bloom-Filter,即布隆过滤器,1970年由Bloom中提出。它可以用于检索一个元素是否在一个集合中。
Bloom Filter是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。它是一个判断元素是否存在集合的快速的概率算法。Bloom Filter有可能会出现错误判断,但不会漏掉判断。也就是Bloom Filter判断元素不在集合,那肯定不在。如果判断元素存在集合中,有一定的概率判断错误。因此,Bloom Filter不适合那些“零错误的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter比其他常见的算法(如hash,折半查找)极大节省了空间。
优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
bloom原理
布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
不保证查找的结果是100%正确的
主要如下4个参数:
m | bit数组的宽度(bit数) |
n | 加入其中的key的数量 |
k | 使用的hash函数的个数 |
fpp | False Positive的比率 |
在使用bloom filter时,绕不过的两点是预估数据量n以及期望的误判率fpp。
在实现bloom filter时,绕不过的两点就是hash函数的选取以及bit数组的大小。
错误率公式:
Bit数组大小选择:
根据预估数据量n以及误判率fpp,bit数组大小的m的计算方式:
哈希函数选择:
由预估数据量n以及bit数组长度m,可以得到一个hash函数的个数k
工程应用
场景
过滤最近30天的曝光记录
方案
1、实时数据,当日曝光实时写入redis
2、前29天的历史数据使用bloom filter过滤
a、曝光记录每日定时从数据库中计算离线写入ftp
b、业务方从ftp拉取曝光记录到本地,然后计算写入本机bloom filter
c、本机只保留最近29天的bloom filter,每次拉取新一天的数据时剔除前一日的数据
3、数据过滤时使用bloom + redis进行数据过滤
实现
基于go语言进行选型
1、github.com/tylertreat/BoomFilters
星标高
支持丰富
监控项全
2、container/list
List存储最近29天的bloom filter,每次加入新bloom时剔除最老的数据