PHP中實現Bloom Filter演算法_php技巧

來源:互聯網
上載者:User
<?php/*Bloom Filter演算法來去重過濾。介紹下Bloom Filter的基本處理思路:申請一批空間用於儲存0 1資訊,再根據一批雜湊函數確定元素對應的位置,如果每個雜湊函數對應位置的值為全部1,說明此元素存在。相反,如果為0,則要把對應位置的值設定為1。由於不同的元素可能會有相同的雜湊值,即同一個位置有可能儲存了多個元素的資訊,從而導致存在一定的誤判率。如果申請空間太小,隨著元素的增多,1會越來越多,各個元素衝突的機會越來越來大,導致誤判率會越來越大。另外雜湊函數的選擇及個數上也要平衡好,多個雜湊函數雖然可以提供判斷的準確性,但是會降低程式的處理速度,而雜湊函數的增加又要求有更多的空間來儲存位置資訊。Bloom-Filter的應用。  Bloom-Filter一般用於在大資料量的集合中判定某元素是否存在。例如郵件伺服器中的垃圾郵件過濾器。在搜尋引擎領域,Bloom-Filter最常用於網路蜘蛛(Spider)的URL過濾,網路蜘蛛通常有一個 URL列表,儲存著將要下載和已經下載的網頁的URL,網路蜘蛛下載了一個網頁,從網頁中提取到新的URL後,需要判斷該URL是否已經存在於列表中。此時,Bloom-Filter演算法是最好的選擇。   比如說,一個象 Yahoo,Hotmail 和 Gmai 那樣的公眾電子郵件(email)供應商,總是需要過濾來自發送垃圾郵件的人(spamer)的垃圾郵件。一個辦法就是記錄下那些發垃圾郵件的 email 地址。由於那些寄件者不停地在註冊新的地址,全世界少說也有幾十億個發垃圾郵件的地址,將他們都存起來則需要大量的網路伺服器。   布隆過濾器是由巴頓.布隆於一九七零年提出的。它實際上是一個很長的二進位向量和一系列隨機映射函數。我們通過上面的例子來說明起工作原理。  假定我們儲存一億個電子郵件地址,我們先建立一個十六億二進位(位元),即兩億位元組的向量,然後將這十六億個二進位位全部設定為零。對於每一個電子郵件地址 X,我們用八個不同的隨機數產生器(F1,F2, ...,F8) 產生八個資訊指紋(f1, f2, ..., f8)。再用一個隨機數產生器 G 把這八個資訊指紋映射到 1 到十六億中的八個自然數 g1, g2, ...,g8。現在我們把這八個位置的二進位位全部設定為一。當我們對這一億個 email 地址都進行這樣的處理後。一個針對這些 email 地址的布隆過濾器就建成了。(見下圖) 現在,讓我們看看如何用布隆過濾器來檢測一個可疑的電子郵件地址 Y 是否在黑名單中。我們用相同的八個隨機數產生器(F1, F2, ..., F8)對這個地址產生八個資訊指紋 s1,s2,...,s8,然後將這八個指紋對應到布隆過濾器的八個二進位位,分別是 t1,t2,...,t8。如果 Y 在黑名單中,顯然,t1,t2,..,t8 對應的八個二進位一定是一。這樣在遇到任何在黑名單中的電子郵件地址,我們都能準確地發現。   布隆過濾器決不會漏掉任何一個在黑名單中的可疑地址。但是,它有一條不足之處。也就是它有極小的可能將一個不在黑名單中的電子郵件地址判定為在黑名單中,因為有可能某個好的郵件地址正巧對應八個都被設定成一的二進位位。好在這種可能性很小。我們把它稱為誤識機率。在上面的例子中,誤識機率在萬分之一以下。   布隆過濾器的好處在於快速,省空間。但是有一定的誤識別率。常見的補救辦法是在建立一個小的白名單,儲存那些可能別誤判的郵件地址。  */// 使用php程式來描述上面的演算法 $set = array(1,2,3,4,5,6);// 判斷5是否在$set 中 $bloomFiter = array(0,0,0,0,0,0,0,0,0,0);// 通過某種演算法改變$bloomFiter 中位元組表示集合,這裡我們使用簡單的演算法,把集合中對應的value 對應到bloom中的位置變成1 // 演算法如下 foreach($set as $key){$bloomFiter[$key] = 1 ;}var_dump($bloomFiter) ; //此時 $bloomFiter = array(1,1,1,1,1,1);//判斷是否在集合中 if($bloomFiter[9] ==1){ echo '在set 中';  }else{ echo '不在set 中' ; }   // 上面只是一個簡單的例子,實際上雜湊演算法需要好幾個,但另一方面,如果雜湊函數的個數少,那麼位元組中的0就多   class bloom_filter { function __construct($hash_func_num=1, $space_group_num=1) {  $max_length = pow(2, 25);  $binary = pack('C', 0);  //1位元組佔用8位  $this->one_num = 8;  //預設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位,然後十六進位轉換為十進位  $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個雜湊值,目前是最多7個$hash_func_num = 6;//分配1個儲存空間,每個空間為32M,理論上是空間越大誤判率越低,注意php.ini中可使用的記憶體限制$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());

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.