一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - PHP教程 - PHP中實(shí)現(xiàn)Bloom Filter算法

PHP中實(shí)現(xiàn)Bloom Filter算法

2020-09-15 16:13PHP中文網(wǎng) PHP教程

這篇文章主要介紹了PHP中實(shí)現(xiàn)Bloom Filter算法,本文直接給出實(shí)現(xiàn)代碼,代碼中給出詳細(xì)注釋,Bloom Filter算法介紹等內(nèi)容,需要的朋友可以參考下

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?php
 
/*Bloom Filter算法來去重過濾。
 
 
介紹下Bloom Filter的基本處理思路:申請(qǐng)一批空間用于保存0 1信息,再根據(jù)一批哈希函數(shù)確定元素對(duì)應(yīng)的位置,如果每個(gè)哈希函數(shù)對(duì)應(yīng)位置的值為全部1,說明此元素存在。相反,如果為0,則要把對(duì)應(yīng)位置的值設(shè)置為1。由于不同的元素可能會(huì)有相同的哈希值,即同一個(gè)位置有可能保存了多個(gè)元素的信息,從而導(dǎo)致存在一定的誤判率。
 
如果申請(qǐng)空間太小,隨著元素的增多,1會(huì)越來越多,各個(gè)元素沖突的機(jī)會(huì)越來越來大,導(dǎo)致誤判率會(huì)越來越大。另外哈希函數(shù)的選擇及個(gè)數(shù)上也要平衡好,多個(gè)哈希函數(shù)雖然可以提供判斷的準(zhǔn)確性,但是會(huì)降低程序的處理速度,而哈希函數(shù)的增加又要求有更多的空間來存儲(chǔ)位置信息。
 
Bloom-Filter的應(yīng)用。
  Bloom-Filter一般用于在大數(shù)據(jù)量的集合中判定某元素是否存在。例如郵件服務(wù)器中的垃圾郵件過濾器。在搜索引擎領(lǐng)域,Bloom-Filter最常用于網(wǎng)絡(luò)蜘蛛(Spider)的URL過濾,網(wǎng)絡(luò)蜘蛛通常有一個(gè) URL列表,保存著將要下載和已經(jīng)下載的網(wǎng)頁(yè)的URL,網(wǎng)絡(luò)蜘蛛下載了一個(gè)網(wǎng)頁(yè),從網(wǎng)頁(yè)中提取到新的URL后,需要判斷該URL是否已經(jīng)存在于列表中。此時(shí),Bloom-Filter算法是最好的選擇。
  比如說,一個(gè)象 Yahoo,Hotmail 和 Gmai 那樣的公眾電子郵件(email)提供商,總是需要過濾來自發(fā)送垃圾郵件的人(spamer)的垃圾郵件。一個(gè)辦法就是記錄下那些發(fā)垃圾郵件的 email 地址。由于那些發(fā)送者不停地在注冊(cè)新的地址,全世界少說也有幾十億個(gè)發(fā)垃圾郵件的地址,將他們都存起來則需要大量的網(wǎng)絡(luò)服務(wù)器。
 
  布隆過濾器是由巴頓.布隆于一九七零年提出的。它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。我們通過上面的例子來說明起工作原理。
 
  假定我們存儲(chǔ)一億個(gè)電子郵件地址,我們先建立一個(gè)十六億二進(jìn)制(比特),即兩億字節(jié)的向量,然后將這十六億個(gè)二進(jìn)制位全部設(shè)置為零。對(duì)于每一個(gè)電子郵件地址 X,我們用八個(gè)不同的隨機(jī)數(shù)產(chǎn)生器(F1,F2, ...,F8) 產(chǎn)生八個(gè)信息指紋(f1, f2, ..., f8)。再用一個(gè)隨機(jī)數(shù)產(chǎn)生器 G 把這八個(gè)信息指紋映射到 1 到十六億中的八個(gè)自然數(shù) g1, g2, ...,g8。現(xiàn)在我們把這八個(gè)位置的二進(jìn)制位全部設(shè)置為一。當(dāng)我們對(duì)這一億個(gè) email 地址都進(jìn)行這樣的處理后。一個(gè)針對(duì)這些 email 地址的布隆過濾器就建成了。(見下圖) 現(xiàn)在,讓我們看看如何用布隆過濾器來檢測(cè)一個(gè)可疑的電子郵件地址 Y 是否在黑名單中。我們用相同的八個(gè)隨機(jī)數(shù)產(chǎn)生器(F1, F2, ..., F8)對(duì)這個(gè)地址產(chǎn)生八個(gè)信息指紋 s1,s2,...,s8,然后將這八個(gè)指紋對(duì)應(yīng)到布隆過濾器的八個(gè)二進(jìn)制位,分別是 t1,t2,...,t8。如果 Y 在黑名單中,顯然,t1,t2,..,t8 對(duì)應(yīng)的八個(gè)二進(jìn)制一定是一。這樣在遇到任何在黑名單中的電子郵件地址,我們都能準(zhǔn)確地發(fā)現(xiàn)。
  布隆過濾器決不會(huì)漏掉任何一個(gè)在黑名單中的可疑地址。但是,它有一條不足之處。也就是它有極小的可能將一個(gè)不在黑名單中的電子郵件地址判定為在黑名單中,因?yàn)橛锌赡苣硞€(gè)好的郵件地址正巧對(duì)應(yīng)八個(gè)都被設(shè)置成一的二進(jìn)制位。好在這種可能性很小。我們把它稱為誤識(shí)概率。在上面的例子中,誤識(shí)概率在萬(wàn)分之一以下。
  布隆過濾器的好處在于快速,省空間。但是有一定的誤識(shí)別率。常見的補(bǔ)救辦法是在建立一個(gè)小的白名單,存儲(chǔ)那些可能別誤判的郵件地址。
     
     
*/
 
// 使用php程序來描述上面的算法
 
 
$set = array(1,2,3,4,5,6);
// 判斷5是否在$set 中
 
$bloomFiter = array(0,0,0,0,0,0,0,0,0,0);
 
// 通過某種算法改變$bloomFiter 中位數(shù)組表示集合,這里我們使用簡(jiǎn)單的算法,把集合中對(duì)應(yīng)的value 對(duì)應(yīng)到bloom中的位置變成1
 
// 算法如下
 
 
foreach($set as $key){
    
    $bloomFiter[$key] = 1 ;
}
 
var_dump($bloomFiter) ;
 
//此時(shí) $bloomFiter = array(1,1,1,1,1,1);
 
//判斷是否在集合中
 
 if($bloomFiter[9] ==1){
     echo '在set 中';
 }else{
     echo '不在set 中' ;
 }
 
 
 // 上面只是一個(gè)簡(jiǎn)單的例子,實(shí)際上哈希算法需要好幾個(gè),但另一方面,如果哈希函數(shù)的個(gè)數(shù)少,那么位數(shù)組中的0就多
 
 
 class bloom_filter {
 
 function __construct($hash_func_num=1, $space_group_num=1) {
  $max_length = pow(2, 25);
  $binary = pack('C', 0);
 
  //1字節(jié)占用8位
  $this->one_num = 8;
 
  //默認(rèn)32m*1
  $this->space_group_num = $space_group_num;
  $this->hash_space_assoc = array();
 
  //分配空間
  for($i=0; $i<$this->space_group_num; $i++){
   $this->hash_space_assoc[$i] = str_repeat($binary, $max_length);
  }
 
  $this->pow_array = array(
   0 => 1,
   1 => 2,
   2 => 4,
   3 => 8,
   4 => 16,
   5 => 32,
   6 => 64,
   7 => 128,
  );
  $this->chr_array = array();
  $this->ord_array = array();
  for($i=0; $i<256; $i++){
   $chr = chr($i);
   $this->chr_array[$i] = $chr;
   $this->ord_array[$chr] = $i;
  }
 
  $this->hash_func_pos = array(
   0 => array(0, 7, 1),
   1 => array(7, 7, 1),
   2 => array(14, 7, 1),
   3 => array(21, 7, 1),
   4 => array(28, 7, 1),
   5 => array(33, 7, 1),
   6 => array(17, 7, 1),
  );
 
  $this->write_num = 0;
  $this->ext_num = 0;
 
  if(!$hash_func_num){
   $this->hash_func_num = count($this->hash_func_pos);
  }
  else{
   $this->hash_func_num = $hash_func_num;
  }
 }
 
 function add($key) {
  $hash_bit_set_num = 0;
// 離散key
  $hash_basic = sha1($key);
//  截取前4位,然后十六進(jìn)制轉(zhuǎn)換為十進(jìn)制
  $hash_space = hexdec(substr($hash_basic, 0, 4));
//  取模
  $hash_space = $hash_space % $this->space_group_num;
 
  for($hash_i=0; $hash_i<$this->hash_func_num; $hash_i++){
   $hash = hexdec(substr($hash_basic, $this->hash_func_pos[$hash_i][0], $this->hash_func_pos[$hash_i][1]));
   $bit_pos = $hash >> 3;
   $max = $this->ord_array[$this->hash_space_assoc[$hash_space][$bit_pos]];
   $num = $hash - $bit_pos * $this->one_num;
   $bit_pos_value = ($max >> $num) & 0x01;
   if(!$bit_pos_value){
    $max = $max | $this->pow_array[$num];
    $this->hash_space_assoc[$hash_space][$bit_pos] = $this->chr_array[$max];
    $this->write_num++;
   }
   else{
    $hash_bit_set_num++;
   }
  }
  if($hash_bit_set_num == $this->hash_func_num){
   $this->ext_num++;
   return true;
  }
  return false;
 }
 
 function get_stat() {
  return array(
   'ext_num' => $this->ext_num,
   'write_num' => $this->write_num,
  );
 }
}
 
 
//test
//取6個(gè)哈希值,目前是最多7個(gè)
$hash_func_num = 6;
 
//分配1個(gè)存儲(chǔ)空間,每個(gè)空間為32M,理論上是空間越大誤判率越低,注意php.ini中可使用的內(nèi)存限制
$space_group_num = 1;
 
$bf = new bloom_filter($hash_func_num, $space_group_num);
 
$list = array(
 'http://test/1',
 'http://test/2',
 'http://test/3',
 'http://test/4',
 'http://test/5',
 'http://test/6',
 'http://test/1',
 'http://test/2',
);
foreach($list as $k => $v){
 
 if($bf->add($v)){
  echo $v, "\n";
 }
}
print_r($bf->get_stat());

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 免费一级欧美片片线观看 | 猫咪免费人成网站在线观看入口 | 欧美日韩一区二区三区韩大 | 91九色porny国产美女一区 | 久久免费国产 | ai换脸明星造梦工厂忘忧草 | 日韩毛片高清在线看 | 国产成人精品日本亚洲网址 | 欧美一级免费看 | 奶茶视频有容乃大 | 久久精品男人影院 | 美女扒开奶罩让男人吃奶 | 国产99在线 | 久久精品一卡二卡三卡四卡视频版 | 99re热这里只有精品视频 | 欧美日韩精品亚洲精品v18 | 日韩欧美国产免费看清风阁 | 亚洲www视频 | 关晓彤被调教出奶水的视频 | 俺去啦最新 | 久久91精品国产91久久户 | 变形金刚第一部 | 日韩国产欧美精品综合二区 | 热热影院| 午夜勾魂曲| 国产精品免费精品自在线观看 | 国产婷婷成人久久av免费高清 | 日韩成人在线视频 | 午夜精品久久久久久久99蜜桃 | 经典三级四虎在线观看 | 国产一级片视频 | 爱欲荡漾在线观看 | 免费在线电视 | 男人的天堂欧美 | 亚洲欧美午夜 | 亚洲黄色大片 | 射西西| 免费刷10000名片赞网站 | 99久久一香蕉国产线看观看 | 成人免费视频一区二区 | 日韩高清一区二区三区不卡 |