首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現布隆過濾器:海量數據去重與存在性判斷的高效算法

     編輯:PHP 綜合知識

原理介紹

布隆過濾器由位數組與多個哈希函數組成。添加元素時,經各哈希函數映射到位數組的多個位置置 1;查詢時,若所有對應位均為 1 則「可能存在」,若有任一為 0 則「一定不存在」。犧牲微小誤判率(假陽性),換取極高空間效率與 O(k) 時間複雜度。

簡單版演示

$set = [1,2,3,4,5,6];
$bloom = array_fill(0, 10, 0);
foreach ($set as $k) $bloom[$k] = 1;
var_dump($bloom); // [1,1,1,1,1,1,0,0,0,0]
echo $bloom[9] ? '在 set 中' : '不在 set 中'; // 不在

生產級類實現

class bloom_filter {
    private $hash_func_num, $space_group_num, $hash_space_assoc = [], $pow_array, $chr_array, $ord_array, $hash_func_pos;
    private $write_num = 0, $ext_num = 0, $one_num = 8;

    function __construct($hash_func_num = 1, $space_group_num = 1) {
        $max_length = pow(2, 25); // 32MB per group
        $binary = pack('C', 0);
        for ($i=0; $i<$space_group_num; $i++) $this->hash_space_assoc[$i] = str_repeat($binary, $max_length);
        $this->pow_array = [0=>1,1=>2,2=>4,3=>8,4=>16,5=>32,6=>64,7=>128];
        for ($i=0; $i<256; $i++) { $chr=chr($i); $this->chr_array[$i]=$chr; $this->ord_array[$chr]=$i; }
        $this->hash_func_pos = [0=>[0,7,1],1=>[7,7,1],2=>[14,7,1],3=>[21,7,1],4=>[28,7,1],5=>[33,7,1],6=>[17,7,1]];
        $this->hash_func_num = $hash_func_num ?: count($this->hash_func_pos);
        $this->space_group_num = $space_group_num;
    }

    function add($key) {
        $hash_bit_set = 0;
        $hash_basic = sha1($key);
        $hash_space = hexdec(substr($hash_basic,0,4)) % $this->space_group_num;
        for ($i=0; $i<$this->hash_func_num; $i++) {
            $hash = hexdec(substr($hash_basic, $this->hash_func_pos[$i][0], $this->hash_func_pos[$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_val = ($max >> $num) & 0x01;
            if (!$bit_val) {
                $max |= $this->pow_array[$num];
                $this->hash_space_assoc[$hash_space][$bit_pos] = $this->chr_array[$max];
                $this->write_num++;
            } else $hash_bit_set++;
        }
        if ($hash_bit_set == $this->hash_func_num) { $this->ext_num++; return true; }
        return false;
    }

    function get_stat() { return ['ext_num'=>$this->ext_num, 'write_num'=>$this->write_num]; }
}

// 測試
$bf = new bloom_filter(6, 1); // 6 hash, 1 group (32MB)
$list = ['https://test/1','https://test/2','https://test/3','https://test/4','https://test/5','https://test/6','https://test/1','https://test/2'];
foreach ($list as $v) if ($bf->add($v)) echo $v, "\n"; // 僅輸出重複項
print_r($bf->get_stat());

關鍵參數權衡

  • 位數組大小:越大誤判率越低,但佔用內存多。PHP 需在 memory_limit 內。
  • 哈希函數數量:越多判斷越準,但計算與寫入開銷增大。通常 5~7 個為宜。
  • 誤判率估算:(1 - e^(-k*n/m))^k,其中 k=哈希數,n=元素數,m=位數組大小。

應用場景

  • 網絡爬蟲 URL 去重(如原文所述 Yahoo/GMail 垃圾郵件過濾)。
  • 緩存穿透防護:先查布隆,不存在直接返回,避免查空數據庫。
  • 大規模集合交集/差集快速預判。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved