1. Bloom-Filter算法简介

Bloom-Filter,即布隆过滤器,1970年由Bloom中提出。它可以用于检索一个元素是否在一个集合中。

Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。它是一个判断元素是否存在集合的快速的概率算法。Bloom Filter有可能会出现错误判断,但不会漏掉判断。也就是Bloom Filter判断元素不再集合,那肯定不在。如果判断元素存在集合中,有一定的概率判断错误。因此,Bloom Filter不适合那些“零错误”的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter比其他常见的算法(如hash,折半查找)极大节省了空间。

它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

Bloom Filter的详细介绍:Bloom Filter

2、 Bloom-Filter的基本思想

Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。

计算某元素x是否在一个集合中,首先能想到的方法就是将所有的已知元素保存起来构成一个集合R,然后用元素x跟这些R中的元素一一比较来判断是否存在于集合R中;我们可以采用链表等数据结构来实现。但是,随着集合R中元素的增加,其占用的内存将越来越大。试想,如果有几千万个不同网页需要下载,所需的内存将足以占用掉整个进程的内存地址空间。即使用MD5,UUID这些方法将URL转成固定的短小的字符串,内存占用也是相当巨大的。

于是,我们会想到用Hash table的数据结构,运用一个足够好的Hash函数将一个URL映射到二进制位数组(位图数组)中的某一位。如果该位已经被置为1,那么表示该URL已经存在。

Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。

原理要点:一是位数组, 而是k个独立hash函数。

1)位数组:

假设Bloom Filter使用一个m比特的数组来保存信息,初始状态时,Bloom Filter是一个包含m位的位数组,每一位都置为0,即BF整个数组的元素都设置为0。

2)添加元素,k个独立hash函数

为了表达S={x1, x2,…,xn}这样一个n个元素的集合,Bloom Filter使用k个相互独立的哈希函数(Hash Function),它们分别将集合中的每个元素映射到{1,…,m}的范围中。

当我们往Bloom Filter中增加任意一个元素x时候,我们使用k个哈希函数得到k个哈希值,然后将数组中对应的比特位设置为1。即第i个哈希函数映射的位置hashi(x)就会被置为1(1≤i≤k)。

注意,如果一个位置多次被置为1,那么只有第一次会起作用,后面几次将没有任何效果。在下图中,k=3,且有两个哈希函数选中同一个位置(从左边数第五位,即第二个“1“处)。

3)判断元素是否存在集合

在判断y是否属于这个集合时,我们只需要对y使用k个哈希函数得到k个哈希值,如果所有hashi(y)的位置都是1(1≤i≤k),即k个位置都被设置为1了,那么我们就认为y是集合中的元素,否则就认为y不是集合中的元素。下图中y1就不是集合中的元素(因为y1有一处指向了“0”位)。y2或者属于这个集合,或者刚好是一个false positive。

显然这 个判断并不保证查找的结果是100%正确的。

Bloom Filter的缺点:

1)Bloom Filter无法从Bloom Filter集合中删除一个元素。因为该元素对应的位会牵动到其他的元素。所以一个简单的改进就是 counting Bloom filter,用一个counter数组代替位数组,就可以支持删除了。 此外,Bloom Filter的hash函数选择会影响算法的效果。

2)还有一个比较重要的问题,如何根据输入元素个数n,确定位数组m的大小及hash函数个数,即hash函数选择会影响算法的效果。当hash函数个数k=(ln2)*(m/n)时错误率最小。在错误率不大于E的情况 下,m至少要等于n*lg(1/E) 才能表示任意n个元素的集合。但m还应该更大些,因为还要保证bit数组里至少一半为0,则m应 该>=nlg(1/E)*lge ,大概就是nlg(1/E)1.44倍(lg表示以2为底的对数)。

举个例子我们假设错误率为0.01,则此时m应大概是n的13倍。这样k大概是8个。

注意:

这里m与n的单位不同,m是bit为单位,而n则是以元素个数为单位(准确的说是不同元素的个数)。通常单个元素的长度都是有很多bit的。所以使用bloom filter内存上通常都是节省的。

一般BF可以与一些key-value的数据库一起使用,来加快查询。由于BF所用的空间非常小,所有BF可以常驻内存。这样子的话,对于大部分不存在的元素,我们只需要访问内存中的BF就可以判断出来了,只有一小部分,我们需要访问在硬盘上的key-value数据库。从而大大地提高了效率。

一个Bloom Filter有以下参数:

m bit数组的宽度(bit数)
n 加入其中的key的数量
k 使用的hash函数的个数
f False Positive的比率

Bloom Filter的f满足下列公式:

在给定m和n时,能够使f最小化的k值为:

此时给出的f为:

根据以上公式,对于任意给定的f,我们有:

 
n = m ln(0.6185) / ln(f)    [1]
 
同时,我们需要k个hash来达成这个目标:
 
k = - ln(f) / ln(2)             [2]
 
由于k必须取整数,我们在Bloom Filter的程序实现中,还应该使用上面的公式来求得实际的f:
 
f = (1 – e-kn/m)k             [3]
 
以上3个公式是程序实现Bloom Filter的关键公式。

3、 扩展 CounterBloom Filter

CounterBloom Filter

BloomFilter有个缺点,就是不支持删除操作,因为它不知道某一个位从属于哪些向量。那我们可以给Bloom Filter加上计数器,添加时增加计数器,删除时减少计数器。

但这样的Filter需要考虑附加的计数器大小,假如同个元素多次插入的话,计数器位数较少的情况下,就会出现溢出问题。如果对计数器设置上限值的话,会导致Cache Miss,但对某些应用来说,这并不是什么问题,如Web Sharing。

Compressed Bloom Filter

为了能在服务器之间更快地通过网络传输Bloom Filter,我们有方法能在已完成Bloom Filter之后,得到一些实际参数的情况下进行压缩。

将元素全部添加入Bloom Filter后,我们能得到真实的空间使用率,用这个值代入公式计算出一个比m小的值,重新构造Bloom Filter,对原先的哈希值进行求余处理,在误判率不变的情况下,使得其内存大小更合适。

4、 Bloom-Filter的应用

Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。例如邮件服务器中的垃圾邮件过滤器。在搜索引擎领域,Bloom-Filter最常用于网络蜘蛛(Spider)的URL过滤,网络蜘蛛通常有一个URL列表,保存着将要下载和已经下载的网页的URL,网络蜘蛛下载了一个网页,从网页中提取到新的URL后,需要判断该URL是否已经存在于列表中。此时,Bloom-Filter算法是最好的选择。

1.key-value 加快查询

一般Bloom-Filter可以与一些key-value的数据库一起使用,来加快查询。

一般key-value存储系统的values存在硬盘,查询就是件费时的事。将Storage的数据都插入Filter,在Filter中查询都不存在时,那就不需要去Storage查询了。当False Position出现时,只是会导致一次多余的Storage查询。

由于Bloom-Filter所用的空间非常小,所有BF可以常驻内存。这样子的话,对于大部分不存在的元素,我们只需要访问内存中的Bloom-Filter就可以判断出来了,只有一小部分,我们需要访问在硬盘上的key-value数据库。从而大大地提高了效率。如图:

2 .Google的BigTable

Google的BigTable也使用了Bloom Filter,以减少不存在的行或列在磁盘上的查询,大大提高了数据库的查询操作的性能。

3. Proxy-Cache

在Internet Cache Protocol中的Proxy-Cache很多都是使用Bloom Filter存储URLs,除了高效的查询外,还能很方便得传输交换Cache信息。

4.网络应用

1)P2P网络中查找资源操作,可以对每条网络通路保存Bloom Filter,当命中时,则选择该通路访问。

2)广播消息时,可以检测某个IP是否已发包。

3)检测广播消息包的环路,将Bloom Filter保存在包里,每个节点将自己添加入Bloom Filter。

4)信息队列管理,使用Counter Bloom Filter管理信息流量。

5. 垃圾邮件地址过滤

像网易,QQ这样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。

一个办法就是记录下那些发垃圾邮件的 email地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。

如果用哈希表,每存储一亿个 email地址,就需要 1.6GB的内存(用哈希表实现的具体办法是将每一个 email地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email地址需要占用十六个字节。一亿个地址大约要 1.6GB,即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB的内存。

而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解决同样的问题。

BloomFilter决不会漏掉任何一个在黑名单中的可疑地址。而至于误判问题,常见的补救办法是在建立一个小的白名单,存储那些可能别误判的邮件地址。

5、 Bloom-Filter的具体实现

c语言实现:

stdafx.h:

  1. #pragma once
  2. #include <stdio.h>
  3. #include "stdlib.h"
  4. #include <iostream>
  5. #include <time.h>
  6. using namespace std;
  1. #include "stdafx.h"
  2. #define ARRAY_SIZE 256 /*we get the 256 chars of each line*/
  3. #define SIZE 48000000 /* size should be 1/8 of max*/
  4. #define MAX  384000000/*the max bit space*/
  5. #define SETBIT(ch,n) ch[n/8]|=1<<(7-n%8)
  6. #define GETBIT(ch,n) (ch[n/8]&1<<(7-n%8))>>(7-n%8)
  7. unsigned int len(char *ch);/* functions to calculate the length of the url*/
  8. unsigned int RSHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  9. unsigned int JSHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  10. unsigned int PJWHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  11. unsigned int ELFHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  12. unsigned int BKDRHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  13. unsigned int SDBMHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  14. unsigned int DJBHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  15. unsigned int DEKHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  16. unsigned int BPHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  17. unsigned int FNVHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  18. unsigned int APHash(char* str, unsigned int len);/* functions to calculate the hash value of the url*/
  19. unsigned int HFLPHash(char* str,unsigned int len);/* functions to calculate the hash value of the url*/
  20. unsigned int HFHash(char* str,unsigned int len);/* functions to calculate the hash value of the url*/
  21. unsigned int StrHash( char* str,unsigned int len);/* functions to calculate the hash value of the url*/
  22. unsigned int TianlHash(char* str,unsigned int len);/* functions to calculate the hash value of the url*/
  23. int main()
  24. {
  25. int i,num,num2=0; /* the number to record the repeated urls and the total of it*/
  26. unsigned int tt=0;
  27. int flag;         /*it helps to check weather the url has already existed */
  28. char buf[257];    /*it helps to print the start time of the program */
  29. time_t tmp = time(NULL);
  30. char file1[100],file2[100];
  31. FILE *fp1,*fp2;/*pointer to the file */
  32. char ch[ARRAY_SIZE];
  33. char *vector ;/* the bit space*/
  34. vector = (char *)calloc(SIZE,sizeof(char));
  35. printf("Please enter the file with repeated urls:\n");
  36. scanf("%s",&file1);
  37. if( (fp1 = fopen(file1,"rb")) == NULL) {  /* open the goal file*/
  38. printf("Connot open the file %s!\n",file1);
  39. }
  40. printf("Please enter the file you want to save to:\n");
  41. scanf("%s",&file2);
  42. if( (fp2 = fopen(file2,"w")) == NULL) {
  43. printf("Connot open the file %s\n",file2);
  44. }
  45. strftime(buf,32,"%Y-%m-%d %H:%M:%S",localtime(&tmp));
  46. printf("%s\n",buf); /*print the system time*/
  47. for(i=0;i<SIZE;i++) {
  48. vector[i]=0;  /*set 0*/
  49. }
  50. while(!feof(fp1)) { /* the check process*/
  51. fgets(ch,ARRAY_SIZE,fp1);
  52. flag=0;
  53. tt++;
  54. if( GETBIT(vector, HFLPHash(ch,len(ch))%MAX) ) {
  55. flag++;
  56. } else {
  57. SETBIT(vector,HFLPHash(ch,len(ch))%MAX );
  58. }
  59. if( GETBIT(vector, StrHash(ch,len(ch))%MAX) ) {
  60. flag++;
  61. } else {
  62. SETBIT(vector,StrHash(ch,len(ch))%MAX );
  63. }
  64. if( GETBIT(vector, HFHash(ch,len(ch))%MAX) )   {
  65. flag++;
  66. } else {
  67. SETBIT(vector,HFHash(ch,len(ch))%MAX );
  68. }
  69. if( GETBIT(vector, DEKHash(ch,len(ch))%MAX) ) {
  70. flag++;
  71. } else {
  72. SETBIT(vector,DEKHash(ch,len(ch))%MAX );
  73. }
  74. if( GETBIT(vector, TianlHash(ch,len(ch))%MAX) ) {
  75. flag++;
  76. } else {
  77. SETBIT(vector,TianlHash(ch,len(ch))%MAX );
  78. }
  79. if( GETBIT(vector, SDBMHash(ch,len(ch))%MAX) )  {
  80. flag++;
  81. } else {
  82. SETBIT(vector,SDBMHash(ch,len(ch))%MAX );
  83. }
  84. if(flag<6)
  85. num2++;
  86. else
  87. fputs(ch,fp2);
  88. /*  printf(" %d",flag); */
  89. }
  90. /* the result*/
  91. printf("\nThere are %d urls!\n",tt);
  92. printf("\nThere are %d not repeated urls!\n",num2);
  93. printf("There are %d repeated urls!\n",tt-num2);
  94. fclose(fp1);
  95. fclose(fp2);
  96. return 0;
  97. }
  98. /*functions may be used in the main */
  99. unsigned int len(char *ch)
  100. {
  101. int m=0;
  102. while(ch[m]!='\0') {
  103. m++;
  104. }
  105. return m;
  106. }
  107. unsigned int RSHash(char* str, unsigned int len) {
  108. unsigned int b = 378551;
  109. unsigned int a = 63689;
  110. unsigned int hash = 0;
  111. unsigned int i = 0;
  112. for(i=0; i<len; str++, i++) {
  113. hash = hash*a + (*str);
  114. a = a*b;
  115. }
  116. return hash;
  117. }
  118. /* End Of RS Hash Function */
  119. unsigned int JSHash(char* str, unsigned int len)
  120. {
  121. unsigned int hash = 1315423911;
  122. unsigned int i    = 0;
  123. for(i=0; i<len; str++, i++) {
  124. hash ^= ((hash<<5) + (*str) + (hash>>2));
  125. }
  126. return hash;
  127. }
  128. /* End Of JS Hash Function */
  129. unsigned int PJWHash(char* str, unsigned int len)
  130. {
  131. const unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
  132. const unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt  * 3) / 4);
  133. const unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8);
  134. const unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
  135. unsigned int hash = 0;
  136. unsigned int test = 0;
  137. unsigned int i = 0;
  138. for(i=0;i<len; str++, i++) {
  139. hash = (hash<<OneEighth) + (*str);
  140. if((test = hash & HighBits)  != 0) {
  141. hash = ((hash ^(test >> ThreeQuarters)) & (~HighBits));
  142. }
  143. }
  144. return hash;
  145. }
  146. /* End Of  P. J. Weinberger Hash Function */
  147. unsigned int ELFHash(char* str, unsigned int len)
  148. {
  149. unsigned int hash = 0;
  150. unsigned int x    = 0;
  151. unsigned int i    = 0;
  152. for(i = 0; i < len; str++, i++) {
  153. hash = (hash << 4) + (*str);
  154. if((x = hash & 0xF0000000L) != 0) {
  155. hash ^= (x >> 24);
  156. }
  157. hash &= ~x;
  158. }
  159. return hash;
  160. }
  161. /* End Of ELF Hash Function */
  162. unsigned int BKDRHash(char* str, unsigned int len)
  163. {
  164. unsigned int seed = 131; /* 31 131 1313 13131 131313 etc.. */
  165. unsigned int hash = 0;
  166. unsigned int i    = 0;
  167. for(i = 0; i < len; str++, i++)
  168. {
  169. hash = (hash * seed) + (*str);
  170. }
  171. return hash;
  172. }
  173. /* End Of BKDR Hash Function */
  174. unsigned int SDBMHash(char* str, unsigned int len)
  175. {
  176. unsigned int hash = 0;
  177. unsigned int i    = 0;
  178. for(i = 0; i < len; str++, i++) {
  179. hash = (*str) + (hash << 6) + (hash << 16) - hash;
  180. }
  181. return hash;
  182. }
  183. /* End Of SDBM Hash Function */
  184. unsigned int DJBHash(char* str, unsigned int len)
  185. {
  186. unsigned int hash = 5381;
  187. unsigned int i    = 0;
  188. for(i = 0; i < len; str++, i++) {
  189. hash = ((hash << 5) + hash) + (*str);
  190. }
  191. return hash;
  192. }
  193. /* End Of DJB Hash Function */
  194. unsigned int DEKHash(char* str, unsigned int len)
  195. {
  196. unsigned int hash = len;
  197. unsigned int i    = 0;
  198. for(i = 0; i < len; str++, i++) {
  199. hash = ((hash << 5) ^ (hash >> 27)) ^ (*str);
  200. }
  201. return hash;
  202. }
  203. /* End Of DEK Hash Function */
  204. unsigned int BPHash(char* str, unsigned int len)
  205. {
  206. unsigned int hash = 0;
  207. unsigned int i    = 0;
  208. for(i = 0; i < len; str++, i++) {
  209. hash = hash << 7 ^ (*str);
  210. }
  211. return hash;
  212. }
  213. /* End Of BP Hash Function */
  214. unsigned int FNVHash(char* str, unsigned int len)
  215. {
  216. const unsigned int fnv_prime = 0x811C9DC5;
  217. unsigned int hash      = 0;
  218. unsigned int i         = 0;
  219. for(i = 0; i < len; str++, i++) {
  220. hash *= fnv_prime;
  221. hash ^= (*str);
  222. }
  223. return hash;
  224. }
  225. /* End Of FNV Hash Function */
  226. unsigned int APHash(char* str, unsigned int len)
  227. {
  228. unsigned int hash = 0xAAAAAAAA;
  229. unsigned int i    = 0;
  230. for(i = 0; i < len; str++, i++) {
  231. hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ (*str) * (hash >> 3)) :
  232. (~((hash << 11) + (*str) ^ (hash >> 5)));
  233. }
  234. return hash;
  235. }
  236. /* End Of AP Hash Function */
  237. unsigned int HFLPHash(char *str,unsigned int len)
  238. {
  239. unsigned int n=0;
  240. int i;
  241. char* b=(char *)&n;
  242. for(i=0;i<strlen(str);++i) {
  243. b[i%4]^=str[i];
  244. }
  245. return n%len;
  246. }
  247. /* End Of HFLP Hash Function*/
  248. unsigned int HFHash(char* str,unsigned int len)
  249. {
  250. int result=0;
  251. char* ptr=str;
  252. int c;
  253. int i=0;
  254. for (i=1;c=*ptr++;i++)
  255. result += c*3*i;
  256. if (result<0)
  257. result = -result;
  258. return result%len;
  259. }
  260. /*End Of HKHash Function */
  261. unsigned int StrHash( char *str,unsigned int len)
  262. {
  263. register unsigned int   h;
  264. register unsigned char *p;
  265. for(h=0,p=(unsigned char *)str;*p;p++) {
  266. h=31*h+*p;
  267. }
  268. return h;
  269. }
  270. /*End Of StrHash Function*/
  271. unsigned int TianlHash(char *str,unsigned int len)
  272. {
  273. unsigned long urlHashValue=0;
  274. int ilength=strlen(str);
  275. int i;
  276. unsigned char ucChar;
  277. if(!ilength)  {
  278. return 0;
  279. }
  280. if(ilength<=256)  {
  281. urlHashValue=16777216*(ilength-1);
  282. } else {
  283. urlHashValue = 42781900080;
  284. }
  285. if(ilength<=96) {
  286. for(i=1;i<=ilength;i++) {
  287. ucChar=str[i-1];
  288. if(ucChar<='Z'&&ucChar>='A')  {
  289. ucChar=ucChar+32;
  290. }
  291. urlHashValue+=(3*i*ucChar*ucChar+5*i*ucChar+7*i+11*ucChar)%1677216;
  292. }
  293. } else  {
  294. for(i=1;i<=96;i++)
  295. {
  296. ucChar=str[i+ilength-96-1];
  297. if(ucChar<='Z'&&ucChar>='A')
  298. {
  299. ucChar=ucChar+32;
  300. }
  301. urlHashValue+=(3*i*ucChar*ucChar+5*i*ucChar+7*i+11*ucChar)%1677216;
  302. }
  303. }
  304. return urlHashValue;
  305. }
  306. /*End Of Tianl Hash Function*/

网上找到的php简单实现:

  1. <?php
  2. /**
  3. * Implements a Bloom Filter
  4. */
  5. class BloomFilter {
  6. /**
  7. * Size of the bit array
  8. *
  9. * @var int
  10. */
  11. protected $m;
  12. /**
  13. * Number of hash functions
  14. *
  15. * @var int
  16. */
  17. protected $k;
  18. /**
  19. * Number of elements in the filter
  20. *
  21. * @var int
  22. */
  23. protected $n;
  24. /**
  25. * The bitset holding the filter information
  26. *
  27. * @var array
  28. */
  29. protected $bitset;
  30. /**
  31. * 计算最优的hash函数个数:当hash函数个数k=(ln2)*(m/n)时错误率最小
  32. *
  33. * @param int $m bit数组的宽度(bit数)
  34. * @param int $n 加入布隆过滤器的key的数量
  35. * @return int
  36. */
  37. public static function getHashCount($m, $n) {
  38. return ceil(($m / $n) * log(2));
  39. }
  40. /**
  41. * Construct an instance of the Bloom filter
  42. *
  43. * @param int $m bit数组的宽度(bit数) Size of the bit array
  44. * @param int $k hash函数的个数 Number of different hash functions to use
  45. */
  46. public function __construct($m, $k) {
  47. $this->m = $m;
  48. $this->k = $k;
  49. $this->n = 0;
  50. /* Initialize the bit set */
  51. $this->bitset = array_fill(0, $this->m - 1, false);
  52. }
  53. /**
  54. * False Positive的比率:f = (1 – e-kn/m)k
  55. * Returns the probability for a false positive to occur, given the current number of items in the filter
  56. *
  57. * @return double
  58. */
  59. public function getFalsePositiveProbability() {
  60. $exp = (-1 * $this->k * $this->n) / $this->m;
  61. return pow(1 - exp($exp),  $this->k);
  62. }
  63. /**
  64. * Adds a new item to the filter
  65. *
  66. * @param mixed Either a string holding a single item or an array of
  67. *              string holding multiple items.  In the latter case, all
  68. *              items are added one by one internally.
  69. */
  70. public function add($key) {
  71. if (is_array($key)) {
  72. foreach ($key as $k) {
  73. $this->add($k);
  74. }
  75. return;
  76. }
  77. $this->n++;
  78. foreach ($this->getSlots($key) as $slot) {
  79. $this->bitset[$slot] = true;
  80. }
  81. }
  82. /**
  83. * Queries the Bloom filter for an element
  84. *
  85. * If this method return FALSE, it is 100% certain that the element has
  86. * not been added to the filter before.  In contrast, if TRUE is returned,
  87. * the element *may* have been added to the filter previously.  However with
  88. * a probability indicated by getFalsePositiveProbability() the element has
  89. * not been added to the filter with contains() still returning TRUE.
  90. *
  91. * @param mixed Either a string holding a single item or an array of
  92. *              strings holding multiple items.  In the latter case the
  93. *              method returns TRUE if the filter contains all items.
  94. * @return boolean
  95. */
  96. public function contains($key) {
  97. if (is_array($key)) {
  98. foreach ($key as $k) {
  99. if ($this->contains($k) == false) {
  100. return false;
  101. }
  102. }
  103. return true;
  104. }
  105. foreach ($this->getSlots($key) as $slot) {
  106. if ($this->bitset[$slot] == false) {
  107. return false;
  108. }
  109. }
  110. return true;
  111. }
  112. /**
  113. * Hashes the argument to a number of positions in the bit set and returns the positions
  114. *
  115. * @param string Item
  116. * @return array Positions
  117. */
  118. protected function getSlots($key) {
  119. $slots = array();
  120. $hash = self::getHashCode($key);
  121. mt_srand($hash);
  122. for ($i = 0; $i < $this->k; $i++) {
  123. $slots[] = mt_rand(0, $this->m - 1);
  124. }
  125. return $slots;
  126. }
  127. /**
  128. * 使用CRC32产生一个32bit(位)的校验值。
  129. * 由于CRC32产生校验值时源数据块的每一bit(位)都会被计算,所以数据块中即使只有一位发生了变化,也会得到不同的CRC32值。
  130. * Generates a numeric hash for the given string
  131. *
  132. * Right now the CRC-32 algorithm is used.  Alternatively one could e.g.
  133. * use Adler digests or mimick the behaviour of Java's hashCode() method.
  134. *
  135. * @param string Input for which the hash should be created
  136. * @return int Numeric hash
  137. */
  138. protected static function getHashCode($string) {
  139. return crc32($string);
  140. }
  141. }
  142. $items = array("first item", "second item", "third item");
  143. /* Add all items with one call to add() and make sure contains() finds
  144. * them all.
  145. */
  146. $filter = new BloomFilter(100, BloomFilter::getHashCount(100, 3));
  147. $filter->add($items);
  148. //var_dump($filter); exit;
  149. $items = array("firsttem", "seconditem", "thirditem");
  150. foreach ($items as $item) {
  151. var_dump(($filter->contains($item)));
  152. }
  153. /* Add all items with multiple calls to add() and make sure contains()
  154. * finds them all.
  155. */
  156. $filter = new BloomFilter(100, BloomFilter::getHashCount(100, 3));
  157. foreach ($items as $item) {
  158. $filter->add($item);
  159. }
  160. $items = array("fir sttem", "secondit em", "thir ditem");
  161. foreach ($items as $item) {
  162. var_dump(($filter->contains($item)));
  163. }

问题实例】 给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢?

根据这个问题我们来计算下内存的占用,4G=2^32大概是40亿*8大概是340亿bit,n=50亿,如果按出错率0.01算需要的大概是650亿个bit。 现在可用的是340亿,相差并不多,这样可能会使出错率上升些。另外如果这些urlip是一一对应的,就可以转换成ip,则大大简单了。

大数据处理算法--Bloom Filter布隆过滤的更多相关文章

  1. 海量数据处理算法—Bloom Filter

    海量数据处理算法—Bloom Filter 1. Bloom-Filter算法简介 Bloom-Filter,即布隆过滤器,1970年由Bloom中提出.它可以用于检索一个元素是否在一个集合中. Bl ...

  2. 【转】海量数据处理算法-Bloom Filter

    1. Bloom-Filter算法简介 Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合.它是一个判断元素是否存在于 ...

  3. 【转】Bloom Filter布隆过滤器的概念和原理

    转自:http://blog.csdn.net/jiaomeng/article/details/1495500 之前看数学之美丽,里面有提到布隆过滤器的过滤垃圾邮件,感觉到何其的牛,竟然有这么高效的 ...

  4. Bloom Filter 布隆过滤器

    Bloom Filter 是由伯顿.布隆(Burton Bloom)在1970年提出的一种多hash函数映射的快速查找算法.它实际上是一个很长的二进制向量和一些列随机映射函数.应用在数据量很大的情况下 ...

  5. 海量信息库,查找是否存在(bloom filter布隆过滤器)

    Bloom Filter(布隆过滤器) 布隆过滤器用于测试某一元素是否存在于给定的集合中,是一种空间利用率很高的随机数据结构(probabilistic data structure),存在一定的误识 ...

  6. Bloom Filter布隆过滤器原理和实现(1)

    引子 <数学之美>介绍布隆过滤器非常经典: 在日常生活中,包括设计计算机软件时,经常要判断一个元素是否在一个集合中.比如: 在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它 ...

  7. Bloom Filter(布隆过滤器)的概念和原理

    Bloom filter 适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集 基本原理及要点: 对于原理来说很简单,位数组+k个独立hash函数.将hash函数对应的值的位数组置1,查找时 ...

  8. 海量数据处理之Bloom Filter详解

    前言 :  即可能误判    不会漏判   一.什么是Bloom Filter     Bloom Filter是一种空间效率很高的随机数据结构,它的原理是,当一个元素被加入集合时,通过K个Hash函 ...

  9. 浅谈布隆过滤器Bloom Filter

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

随机推荐

  1. js的各种验证

    验证手机号格式是否正确 // 判断是否为手机号 isPoneAvailable: function (pone) { var myreg = /^[1][3,4,5,7,8][0-9]{9}$/; i ...

  2. centos下查看端口占用情况,杀死进程

    第一种:我们知道端口号用下面这种方法 有时候我们知道某个服务端口正在后台运行,想关掉它.比如说我tomcat是8080端口,在后台运行.怎么关掉它呢? 根据端口查看这个进程的pid netstat - ...

  3. cdqz2017-test10-柚的策略(期望DP & 组合数学)

    根据期望的可加性,我们可以算出每一位客人的期望等待时间,将他们累加 即 每一位客人所有可能情况的时间之和 / n! 设S= 每一位客人所有可能情况的时间之和 如果有f(i,p)种方案使客人i是恰好第p ...

  4. Linux 命令详解(六)Linux 守护进程的启动方法

    Linux 守护进程的启动方法 http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html

  5. Ajax提交请求模板

    function methodName() { var params = { }; var url = ''; jQuery.ajax({ type: 'POST', contentType: 'ap ...

  6. webx roadmap

    SpringExt 自定义Spring Schema的例子 基于Spring可扩展Schema提供自定义配置支持 使用SpringExt扩展Webx的示例 扩展点和捐献 一个namespace下可以声 ...

  7. Simple Sort

    题目描述 You are given an unsorted array of integer numbers. Your task is to sort this array and kill po ...

  8. (原创 开源)AppWidge的使用—桌面便利贴

    Android平台的一大特色就是支持桌面插件——AppWidget. 且不说,AppWidget是否会影响系统的流畅性,AppWidget确实是满足了用户个性化和快捷操作的需要. 常见的AppWidg ...

  9. 【Gradle】Gradle环境配置

    Windows环境 下载 作者下载的是gradle-4.1-all.zip,下载地址:http://services.gradle.org/distributions 环境配置 GRADLE_HOME ...

  10. python - 用类写装饰器

    这里用到了__call__的class内置参数 #类装饰器: class zsq(): #本质是定义一个参数,让装饰的主题传递至__call__方法内部 def __init__(self,obj): ...