温故知新-布隆过滤器的基本原理


摘要

本文介绍了布隆过滤器的基本原理,布隆过滤器有非常多的应用场景,在项目开发、大数据推荐系统都有应用。

基本概念

布隆过滤器(Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出。它由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。

  • 优点是空间效率和查询时间都远远超过一般的算法;
  • 缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中)和删除困难,但是没有识别错误的情形(即假反例False negatives,如果某个元素确实没有在该集合中,那么Bloom Filter 是不会报告该元素存在于集合中的,所以不会漏报);

基本原理

如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。但是随着集合中元素的增加,需要的存储空间越来越大,检索速度也越来越慢。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit Array)中的一个点。只要看看这个点是不是1就知道可以集合中有没有它了。这就是布隆过滤器的基本思想。

Hash面临的问题就是冲突。假设 Hash 函数是良好的,如果位阵列长度为 m 个点,如果想将冲突率降低到例如 1%, 这个散列表就只能容纳 m/100 个元素。解决方法也简单,就是使用多个 Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们在说谎,不过直觉上判断这种事情的概率是比较低的。

布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

image-20200611164603625

直观理解,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。优:布隆过滤器在空间和时间方面都有巨大的优势,存储空间和插入/查询时间都是常数;布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势;缺:误算率(False Positive)是其中之一。随着存入的元素数量增加,误算率随之增加;很难从布隆过滤器中删除元素;

算法描述

  • k个hash函数,每个函数可以把key散列成为1个整数;
  • 初始化时,需要一个长度为m比特的数组,每个比特位初始化为0;
  • 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1;
  • 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位;
    • 若其中任一位不为1,则此元素比不在集合中(因为如果在,则在add时已经把对应的k个bits位置为1);
    • 同理所有的比特位都是1,认为在集合中;

误判概率的证明和计算

p 错误概率,m 为bit大小 ,n为需要判断的数据量,k为每次需要取bit位的次数)

假设布隆过滤器中的hash function满足假设:若m为bit数,每个元素都等概率地hash到m个位置中的任何一个,与其它元素被hash到哪个位置无关,则对某一特定bit位在一个元素由某特定hash function插入时没有被置位为1的概率为:

image-20200611164717910

则 k 个hash function中 没有一个对其置位 的概率为:

image-20200611164736162

如果插入了n个元素,但都未将其置位 的概率为:

image-20200611164751335

则此位 被置位的概率为:

image-20200611164806289

现在考虑query阶段,若对应某个待query元素的k bits全部置位为1,则可判定其在集合中。因此将某元素误判的概率为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pAbbmNjS-1591866259573)(https://wiki.ztjy61.com/download/attachments/15145295/5.png?version=1&modificationDate=1560408415000&api=v2)]

由于

image-20200611164820322

,并且

image-20200611164954000

当m很大时趋近于0,所以

image-20200611164940866

现在计算对于给定的m和n,k为何值时可以使得误判率最低。设误判率为k的函数为:

image-20200611164846013

image-20200611164857605

, 则简化为

image-20200611165008876

,两边取对数

image-20200611165024048

两边对k求导

image-20200611165035777

下面求最值

image-20200611165119374

因此,即当

image-20200611165143121

时误判率最低, (k的公式)此时误判率为:

image-20200611165157867

设计和应用布隆过滤器的方法

  • 首先要先由用户决定要add的元素数n和希望的误差率P(fpp)。这也是一个设计完整的布隆过滤器需要用户输入的仅有的两个参数,之后的所有参数将由系统计算,并由此建立布隆过滤器。
  • 系统计算需要的内存大小M bits:

image-20200611165223074

  • 再由m,n得到hash function的个数 k

image-20200611165234790

  • add n个元素至布隆过滤器中,再进行query。根据公式,当k最优时:

image-20200611165250417

  • 因此可验证当P=1%时,存储每个元素需要9.6 bits:

image-20200611165306307

  • 而每当想将误判率降低为原来的1/10,则存储每个元素需要增加4.8 bits:

    image-20200611165318159

  • 9.6 bits/element不仅包含了被置为1的k位,还把包含了没有被置为1的一些位数。6.72bits 才是每个元素对应的为1的bit位数。

    image-20200611165331992

  • 从而使得P(error)最小时:

image-20200611165350053

  • 此概率为某bit位在插入n个元素后未被置位的概率。因此,想保持错误率低,布隆过滤器的空间使用率需为50%

    image-20200611170016218

典型应用场景

  • 黑名单:比如邮件黑名单过滤器,判断邮件地址是否在黑名单中;
  • 网络爬虫:判断某个URL是否已经被爬取过;
  • K-V系统快速判断某个key是否存在:典型的例子有Hbase,Hbase的每个Region中都包含一个BloomFilter,用于在查询时快速判断某个key在该region中是否存在,如果不存在,直接返回,节省掉后续的查询。
  • 搜索引擎中的海量网页去重;
  • leveldb等数据库中快速判断元素是否存在,可以显著减少磁盘访问;

参考阅读

https://www.cnblogs.com/umpjls/p/7319954.html

https://blog.csdn.net/likaiwalkman/article/details/54310757


你的鼓励也是我创作的动力

打赏地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章