Bloom Filter
来源:互联网 发布:淘宝网安全套 编辑:程序博客网 时间:2024/06/02 04:35
一.简介
1. 布隆过滤器 (Bloom Filter)是由Burton Howard Bloom于1970年提出,实际上是一个很长的二进制向量和一系列随机映射函数。
2. 用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。
3. 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
二.基本概念
1. 如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等等数据结构都是这种思路.,但是元素越来越多,存储空间的需求也越来越大,检索速度慢,所以可以利用散列表(哈希)的数据结构。通过一个Hash函数映射到一个位阵列的一个点。
2. 1亿个不重复的正整数(大致范围已知),但是只有1G的内存可用,如何判断该范围内的某个数是否出现在这1亿个数中?最常用的处理办法是利用位图,1*108/1024*1024*8=11.9,也只需要申请12M的内存。(位图主要用于处理整型值一类的问题,而且要求无重复)
3. 如果是一亿个邮件地址,如何判断邮件地址是否在1亿个地址之中?这时可以使用Hash表,但是哈希表不能避免发生碰撞,假设一个邮件只占8个字节,为了保证Hash表的碰撞率,使装填因子在0.5左右,至少需要2*8*10^8/1024*1024*1024 =1.5G存储空间,因此可以使用另外一种数据结构:Bloom Filter.
三.原理:
1. 布隆过滤器需要的是一个位数组(这个和位图有点类似)和k个映射函数(和Hash表类似),在初始状态时,对于长度为m的位数组array,它的所有位都被置为0,如下图所示:
2. 对于有n个元素的集合S={s1,s2......sn},通过k个映射函数{f1,f2,......fk},将集合S中的每个元素sj(1<=j<=n)映射为k个值{g1,g2......gk},然后再将位数组array中相对应的array[g1],array[g2]......array[gk]置为1:
3. 如果要查找某个元素item是否在S中,则通过映射函数{f1,f2.....fk}得到k个值{g1,g2.....gk},然后再判断array[g1],array[g2]......array[gk]是否都为1,若全为1,则item在S中,否则item不在S中.这个就是布隆过滤器的实现原理.
4. 误判的发生有这个可能:就是集合中的若干个元素通过映射之后得到的数值恰巧包括g1,g2,.....gk,那么这种情况下可能会造成误判,但是这个概率很小,一般在万分之一以下:
5. 布隆过滤器的误判率和这k个映射函数的设计有关
6. 布隆过滤器是不允许删除元素的,因为若删除一个元素,可能会发生漏判的情况。不过有一种布隆过滤器的变体Counter Bloom Filter,可以支持删除元素,
四.应用
1. 布隆过滤器在很多场合能发挥很好的效果,比如:网页URL的去重,垃圾邮件的判别,集合重复元素的判别,查询加速(比如基于key-value的存储系统)等
2. .有两个URL集合A,B,每个集合中大约有1亿个URL,每个URL占64字节,有1G的内存,如何找出两个集合中重复的URL.
很显然,直接利用Hash表会超出内存限制的范围.这里给出两种思路:
第一种:如果不允许一定的错误率的话,只有用分治的思想去解决,将A,B两个集合中的URL分别存到若干个文件中{f1,f2...fk}和{g1,g2....gk}中,然后取f1和g1的内容读入内存,将f1的内容存储到hash_map当中,然后再取g1中的url,若有相同的url,则写入到文件中,然后直到g1的内容读取完毕,再取g2...gk.然后再取f2的内容读入内存...依次类推,知道找出所有的重复url.
第二种:如果允许一定错误率的话,则可以用布隆过滤器的思想. 2.在进行网页爬虫时,其中有一个很重要的过程是重复URL的判别,如果将所有的url存入到数据库中,当数据库中URL的数量很多时,在判重时会造成效率低下,此时常见的一种做法就是利用布隆过滤器,还有一种方法是利用berkeley db来存储url,Berkeley db是一种基于key-value存储的非关系数据库引擎,能够大大提高url判重的效率.
五.例子:
#include <string.h>#include <bitset>#include <iostream>#define MAX 2<<24using namespace std;//简化n,p 生成m的过程,直接初始化为2<<24大小bitset<MAX> bloomSet;//哈希函数的7个种子int seeds[7] = {3,7,11,13,31,37,61};//Hash Valueint getHashValue(string str,int n){int result = 0;int i = 0;for(i = 0;i<str.size();i++){result = seeds[n]*result+(int)str[i];if(result > 2<<24)result %= 2<<24;}return result;}//判断是否在布隆过滤器中bool isInBloomSet(string str){int i;for(i = 0;i<7;i++){int hash = getHashValue(str,i);if(bloomSet[hash] == 0)return false;}return true;}//add Elementsvoid addToBloomSet(string str){int i;for(int i=0;i<7;i++){int hash = getHashValue(str,i);bloomSet.set(hash,1);}}//init the BloomSetvoid initBloomSet(){addToBloomSet("www.baidu.com");addToBloomSet("www.cnblogs.com");addToBloomSet("www.google.com");}int main(int argc, char *argv[]){ int n; initBloomSet(); while(scanf("%d",&n)==1){ string str; while(n--){ cin >> str; if(isInBloomSet(str)){ cout <<"YES"<<endl; }else{ cout <<"NO"<<endl; } } } //system("PAUSE"); return 0;}
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- bloom filter
- bloom filter
- Bloom Filter
- Bloom Filter
- bloom filter
- bloom filter
- bloom filter
- Bloom filter
- Bloom filter
- Bloom Filter
- 设计模式之工厂方法
- svnant
- 玩玩Windows Azure
- 移植java web 项目到go语言要解决的一系列问题
- rmi入门
- Bloom Filter
- HDU 2007
- VC下显示位图的几种方法
- Linux下yum命令概要与用法
- strstr fuction
- UVA 11783 Nail【简单线段相交判断 附YY加强版】
- MFC中怎样将位图写入指定的Picture控件中,两种方式:1 加载已有位图 2读取位图文件;另外CreateDIBitmap的用法和StretchDIBits用法举例
- maven3 自学笔记(一) Maven依赖
- A类不能实例化,但B类需要使用A类对象的设计策略