原文:蘑菇先生,http://www.cnblogs.com/mushroom/p/4556801.html

背景介绍

Bloom filter(后面简称BF)是Bloom在1970年提出的二进制向量数据结构。通俗来说就是在大数据集合下高效判断某个成员是否属于这个集合。BF其优点在于:

  • 插入和查询复杂度都是O(n)
  • 空间利用率极高。

例子1:

像Yahoo这类的公共邮件服务提供商,总是需要过滤垃圾邮件。 假设有50亿个邮件地址,需要存储过滤的方法有:

  1. 所有邮件地址都存储到数据库。
    缺点:每次都需要查询数据库,效率低。
  2. 使用Hashtable保存到内存里,接近O(1)的查询效率。
    缺点:太占内存,假定每个地址需要十六个字符,50亿个需要180G内存。
  3. 创建位数组,将每个邮件地址用Hash函数映射到位数组中的某一位。
    缺点: 单个Hash函数冲突太高,会发生多个邮件会映射到同一位上。

而使用BF可以最大限度避免上述缺点,使其可以在更小空间上,进行高效插入和查询。

例子2:

经常使用缓存的肯定知道,命中率是个永远的话题。 特别是在分布式缓存中,每次不命中就意味着一次跨网络通信的浪费,无故增加缓存服务器压力。使用BF可以在很大程度上提高缓存命中率。

算法原理

BF很合适解决类似上面的问题。 BF和例子1中的第三种方法非常类似了。不同的是,BF对同一个邮件地址使用多个不同的Hash函数,再去映射位数组的中对应位置。

算法步骤:

  1. 创建长度为m的位数组,全部置为0。
  2. 取出邮件地址集合(m)中的某一个地址(a), 分别使用k个hash函数对a计算。
  3. 将结果分别映射到位数组中,并设置为1。
  4. 其他成员依次处理。

以函数个数k=8来算,50亿个邮件地址只需要5G内存足够了,比例子1中方法2节省32倍空间。

当查询成员a时是否在垃圾邮件集合m中时,使用同样k个hash函数进行计算,如果k个结果在位数组中的位值都是1,则判断a属于m集合中,即a邮件地址属于垃圾邮件地址集合m(a∈m)。

关于例子2,可以将所有key存储到本地内存中,每次远程获取缓存时,优先在内存集合中判断是否存在。

  1. 存在?去远程获取实际缓存内容。
  2. 不存在?直接返回,无需再去远程缓存服务器判断。

这样能极大提高缓存命中率,因为BF存在误判率,所有并不能达到100%(在key的数量级不高时,用其他方法全存下来也可以)。如图:

误判率

因为BF使用Hash函数来取得成员的特征(可理解为成员的指纹信息),并没有在位数组中存储集合内的实际数据内容,所以空间利用率极高,但存在个潜在问题,就是查询某个成员是否属于集合时,会发生误判(False positive)。 也就是说,某个成员实际不在集合中,但BF会得出在集中的结论。 所以BF适用于允许发生一定误判的场景,如例子1、2中少量过滤失败或去服务器拿都是可以接受的。

为什么会有误判?

假定有一个长度12的位数组,使用3个hash函数,根据算法计算成员a得出3、7、11位置,并在位数组中设置为1。 另外个成员b根据算法也计算得出3、7、11,去位数组检查其位值时,就发现3、7、11都为1是存在的,而实际不存在(1是成员a设置的),此时就发生了误判现象。

BF会发生误判,但不会发生漏判(False Negative),即成员实际在集合中,那么BF一定能判断出在集合中,因为成员对应的位置都设置为1了。

可控制性

根据其数组长度m、集合大小n、hash函数个数k、误判率p,简单得出下:

  1. 其他不变,集合大小n越大,越多位被设置1,误判率p越大。
  2. 其他不变,数组涨肚m越大,剩余为0的位越多,误判率p越小
  3. 其他不变,添加时k越多,位数组越多被设置为1,即会增大误判率。查询时k越多,明显误判率可能就会越小。

hash函数个数取值公式 k = ln 2 * m/n 。

其他它关系公式见wiki

BF改进

基本的BF在使用时有个缺点:无法删除集合成员a,只能增加其成员并对其查询。 有一个很容易想到但错误的方法是:如果要删除成员a,那么先用k个hash函数对其计算,因为a已经是集合成员,那么其对应的位数组的位置一定被设置为1,所以只要将对应位置重新设置为0即可。   原因就是位数组的位置不但只提供给a使用,也给其他成员使用,一旦设置为0就会影响其他成员的使用。

比如上面中提高缓存命中率的例子,不能删除成员意味着实际缓存也不能删除。如果实际缓存删除了,而在集合中的数据无法删除,就会发生漏判现象。 这样的话就会大大限制BF的使用场景。

计数BF(count bloom filter)

计数BF是对基本BF的改进,使BF可以支持删除成员。  因为BF的基本单位是1个bit,只能表达2种状态,即存在、不存在。 如果把基本单位1bit拓展成多个bit,这样就能增加更多信息,表达出多种状态。

计数BF的基本单元由多个bit表示,一般情况为3、4个bit。  这样在添加时,在数组位置上的数值上加1即可,删除成员时-1即可。 查询集合成员时保持不变,只要数值不为0即认为成员是存在的。

计数BF使基本BF有了更多应用场景。 同样由于用了多个bit来表示,对应数组大小也相应增加,如果用3bit作为基本单位,那么数组大小对应增加了3倍。

总结

BF是大数据处理的利器,其使用场景非常多:

  • Google的爬虫重复URL检测。
  • 黑名单验证。
  • 例子中的缓存命中率,垃圾邮件过滤。
  • 内存挡一层,减轻db空查压力。
  • hbase、LevelDB内部使用。

基本BF的具体实现可参考 http://bloomfilter.codeplex.com。

参考资料

[1] http://en.wikipedia.org/wiki/Bloom_filter

[2] http://www.cnblogs.com/heaad/archive/2011/01/02/1924195.html

【转】探索C#之布隆过滤器(Bloom filter)的更多相关文章

  1. 探索C#之布隆过滤器(Bloom filter)

    阅读目录: 背景介绍 算法原理 误判率 BF改进 总结 背景介绍 Bloom filter(后面简称BF)是Bloom在1970年提出的二进制向量数据结构.通俗来说就是在大数据集合下高效判断某个成员是 ...

  2. [转载]布隆过滤器(Bloom Filter)

    [转载]布隆过滤器(Bloom Filter) 这部分学习资料来源:https://www.youtube.com/watch?v=v7AzUcZ4XA4 Filter判断不在,那就是肯定不在:Fil ...

  3. 布隆过滤器(Bloom Filter)详解——基于多hash的概率查找思想

    转自:http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html   布隆过滤器[1](Bloom Filter)是由布隆(Burton ...

  4. 布隆过滤器(Bloom Filter)的原理和实现

    什么情况下需要布隆过滤器? 先来看几个比较常见的例子 字处理软件中,需要检查一个英语单词是否拼写正确 在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上 在网络爬虫里,一个网址是否被访问过 yahoo, ...

  5. [转载] 布隆过滤器(Bloom Filter)详解

    转载自http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html   布隆过滤器[1](Bloom Filter)是由布隆(Burton ...

  6. 布隆过滤器(Bloom Filter)详解

    直观的说,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中.和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一 ...

  7. 浅谈布隆过滤器Bloom Filter

    先从一道面试题开始: 给A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL. 这个问题的本质在于判断一个元素是否在一个集合中.哈希表以O(1) ...

  8. 【面试突击】-缓存击穿(布隆过滤器 Bloom Filter)

    原文地址:https://blog.csdn.net/fouy_yun/article/details/81075432 前面的文章介绍了缓存的分类和使用的场景.通常情况下,缓存是加速系统响应的一种途 ...

  9. 布隆过滤器 Bloom Filter 2

    date: 2020-04-01 17:00:00 updated: 2020-04-01 17:00:00 Bloom Filter 布隆过滤器 之前的一版笔记 点此跳转 1. 什么是布隆过滤器 本 ...

随机推荐

  1. 分享几个原生javascript面向对象设计小游戏

    一.序言 不知大家是不是和我一样,当初都有个梦想.学编程,就是想开发游戏.结果进入大学学习之后,才知道搞的是数据库应用程序开发!在此,本人就分享下业余时间做的几个小游戏吧!本打算想用winform或w ...

  2. Windows线程漫谈界面线程和工作者线程

    每个系统都有线程,而线程的最重要的作用就是并行处理,提高软件的并发率.针对界面来说,还能提高界面的响应力. 线程分为界面线程和工作者线程,界面实际就是一个线程画出来的东西,这个线程维护一个“消息队列” ...

  3. Eclipse使用多个Console

    调试程序时,有时需要同时使用多个Console,如一个Console运行Server,一个Console运行Client.而一般情况下Eclipse只有一个Console,这时就需要增加一个Conso ...

  4. Malformed \uxxxx encoding解决方法

    java.lang.IllegalArgumentException: Malformed \uxxxx encoding. at java.util.Properties.loadConvert(U ...

  5. 修正 ListView 搜寻问题

    问题:如果 SearchEdit 里已输入过搜寻字,再新建 ListView 项目后,会无法显示. 适用:Delphi XE5 源码下载:[原创]修正ListView搜寻问题.zip procedur ...

  6. mybaits 框架运用

    支持普通 SQL 查询,存储过程和高级映射的ORM持久层框架.以一 个 SqlSessionFactory 对象的实例为核心. 从 XML 中构建 SqlSessionFactory configur ...

  7. 阿里云centos6.5下搭建javaWeb运行环境

    一.主要方法 http://blog.csdn.net/hdfyq/article/details/38456981 上面文章的步骤至mysql安装完毕以及设置(记住 update user set ...

  8. IOS个人帐号推送证书创建

    (IOS个人帐号推送证书制作所有步骤: 可以直接将产品推送证书和开发者推送证书一起制作到一个Identifier帐号下) 一. 首先需要创建一个id:有推送功能的(App ID Suffix)只有它才 ...

  9. javascript(定时函数)

    一setTimeout函数和setInterval函数的语法以及应用 1.setTimeout函数 定义和用法:setTimeout()方法用于在指定的毫秒数后调用函数或计算表达式. 语法:setTi ...

  10. Android应用开发基础之十:多媒体编程

    多媒体概念 文字.图片.音频.视频 计算机图片大小的计算 图片大小 = 图片的总像素 * 每个像素占用的大小 单色图:每个像素占用1/8个字节 16色图:每个像素占用1/2个字节 256色图:每个像素 ...