溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何使用php+redis實現(xiàn)布隆過濾器

發(fā)布時間:2022-03-25 10:23:39 來源:億速云 閱讀:229 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“如何使用php+redis實現(xiàn)布隆過濾器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何使用php+redis實現(xiàn)布隆過濾器”吧!

首先定義一個hash函數(shù)集合類,這些hash函數(shù)不一定都用到,實際上32位hash值的用3個就可以了,具體的數(shù)量可以根據(jù)你的位序列總量和你需要存入的量決定,上面已經(jīng)給出最佳值。

class BloomFilterHash
{
    /**
     * 由Justin Sobel編寫的按位散列函數(shù)
     */
    public function JSHash($string, $len = null)
    {
        $hash = 1315423911;
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash ^= (($hash << 5) + ord($string[$i]) + ($hash >> 2));
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 該哈希算法基于AT&T貝爾實驗室的Peter J. Weinberger的工作。
     * Aho Sethi和Ulman編寫的“編譯器(原理,技術(shù)和工具)”一書建議使用采用此特定算法中的散列方法的散列函數(shù)。
     */
    public function PJWHash($string, $len = null)
    {
        $bitsInUnsignedInt = 4 * 8; //(unsigned int)(sizeof(unsigned int)* 8);
        $threeQuarters = ($bitsInUnsignedInt * 3) / 4;
        $oneEighth = $bitsInUnsignedInt / 8;
        $highBits = 0xFFFFFFFF << (int) ($bitsInUnsignedInt - $oneEighth);
        $hash = 0;
        $test = 0;
        $len || $len = strlen($string);
        for($i=0; $i<$len; $i++) {
            $hash = ($hash << (int) ($oneEighth)) + ord($string[$i]); } $test = $hash & $highBits; if ($test != 0) { $hash = (($hash ^ ($test >> (int)($threeQuarters))) & (~$highBits));
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 類似于PJW Hash功能,但針對32位處理器進(jìn)行了調(diào)整。它是基于UNIX的系統(tǒng)上的widley使用哈希函數(shù)。
     */
    public function ELFHash($string, $len = null)
    {
        $hash = 0;
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash = ($hash << 4) + ord($string[$i]); $x = $hash & 0xF0000000; if ($x != 0) { $hash ^= ($x >> 24);
            }
            $hash &= ~$x;
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 這個哈希函數(shù)來自Brian Kernighan和Dennis Ritchie的書“The C Programming Language”。
     * 它是一個簡單的哈希函數(shù),使用一組奇怪的可能種子,它們都構(gòu)成了31 .... 31 ... 31等模式,它似乎與DJB哈希函數(shù)非常相似。
     */
    public function BKDRHash($string, $len = null)
    {
        $seed = 131;  # 31 131 1313 13131 131313 etc..
        $hash = 0;
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash = (int) (($hash * $seed) + ord($string[$i]));
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 這是在開源SDBM項目中使用的首選算法。
     * 哈希函數(shù)似乎對許多不同的數(shù)據(jù)集具有良好的總體分布。它似乎適用于數(shù)據(jù)集中元素的MSB存在高差異的情況。
     */
    public function SDBMHash($string, $len = null)
    {
        $hash = 0;
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash = (int) (ord($string[$i]) + ($hash << 6) + ($hash << 16) - $hash);
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 由Daniel J. Bernstein教授制作的算法,首先在usenet新聞組comp.lang.c上向世界展示。
     * 它是有史以來發(fā)布的最有效的哈希函數(shù)之一。
     */
    public function DJBHash($string, $len = null)
    {
        $hash = 5381;
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash = (int) (($hash << 5) + $hash) + ord($string[$i]);
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * Donald E. Knuth在“計算機編程藝術(shù)第3卷”中提出的算法,主題是排序和搜索第6.4章。
     */
    public function DEKHash($string, $len = null)
    {
        $len || $len = strlen($string);
        $hash = $len;
        for ($i=0; $i<$len; $i++) {
            $hash = (($hash << 5) ^ ($hash >> 27)) ^ ord($string[$i]);
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }

    /**
     * 參考 http://www.isthe.com/chongo/tech/comp/fnv/
     */
    public function FNVHash($string, $len = null)
    {
        $prime = 16777619; //32位的prime 2^24 + 2^8 + 0x93 = 16777619
        $hash = 2166136261; //32位的offset
        $len || $len = strlen($string);
        for ($i=0; $i<$len; $i++) {
            $hash = (int) ($hash * $prime) % 0xFFFFFFFF;
            $hash ^= ord($string[$i]);
        }
        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;
    }
}

接著就是連接redis來進(jìn)行操作

/**
 * 使用redis實現(xiàn)的布隆過濾器
 */
abstract class BloomFilterRedis
{
    /**
     * 需要使用一個方法來定義bucket的名字
     */
    protected $bucket;

    protected $hashFunction;

    public function __construct($config, $id)
    {
        if (!$this->bucket || !$this->hashFunction) {
            throw new Exception("需要定義bucket和hashFunction", 1);
        }
        $this->Hash = new BloomFilterHash;
        $this->Redis = new YourRedis; //假設(shè)這里你已經(jīng)連接好了
    }

    /**
     * 添加到集合中
     */
    public function add($string)
    {
        $pipe = $this->Redis->multi();
        foreach ($this->hashFunction as $function) {
            $hash = $this->Hash->$function($string);
            $pipe->setBit($this->bucket, $hash, 1);
        }
        return $pipe->exec();
    }

    /**
     * 查詢是否存在, 如果曾經(jīng)寫入過,必定回true,如果沒寫入過,有一定幾率會誤判為存在
     */
    public function exists($string)
    {
        $pipe = $this->Redis->multi();
        $len = strlen($string);
        foreach ($this->hashFunction as $function) {
            $hash = $this->Hash->$function($string, $len);
            $pipe = $pipe->getBit($this->bucket, $hash);
        }
        $res = $pipe->exec();
        foreach ($res as $bit) {
            if ($bit == 0) {
                return false;
            }
        }
        return true;
    }

}

上面定義的是一個抽象類,如果要使用,可以根據(jù)具體的業(yè)務(wù)來使用。比如下面是一個過濾重復(fù)內(nèi)容的過濾器。

/**
 * 重復(fù)內(nèi)容過濾器
 * 該布隆過濾器總位數(shù)為2^32位, 判斷條數(shù)為2^30條. hash函數(shù)最優(yōu)為3個.(能夠容忍最多的hash函數(shù)個數(shù))
 * 使用的三個hash函數(shù)為
 * BKDR, SDBM, JSHash
 *
 * 注意, 在存儲的數(shù)據(jù)量到2^30條時候, 誤判率會急劇增加, 因此需要定時判斷過濾器中的位為1的的數(shù)量是否超過50%, 超過則需要清空.
 */
class FilteRepeatedComments extends BloomFilterRedis
{
    /**
     * 表示判斷重復(fù)內(nèi)容的過濾器
     * @var string
     */
    protected $bucket = 'rptc';

    protected $hashFunction = array('BKDRHash', 'SDBMHash', 'JSHash');
}

到此,相信大家對“如何使用php+redis實現(xiàn)布隆過濾器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI