布隆過濾器

  • 布隆過濾器
    他實際上是一個很長的二進制向量和一系列隨機映射函數,用於檢索一個元素是否在一個集合中,當一個元素被加入到集合中,通過K個hash函數將元素映射到位隊列的K個點中,即將對應的比特位置爲1,檢索時我們只需要知道這些點是不是1就能大約知道這個元素是不是再集合中。如果這些點中任何一個爲0,就一定不存在。如果這些點每個都爲1,那麼元素可能存在在集合中。

  • 實現布隆過濾器

bitMap.h

#pragma once
#include<iostream>
#include<stdlib.h>
#include<vector>
using namespace std;
class bitMap
{
public:
    bitMap(size_t size = 100)
    {
        _vc.resize((size >> 5) + 1);
    }
    void set(size_t key)
    {
        size_t byte = key >> 5;
        size_t bit = key % 32;
        _vc[byte] |= (1 << bit);
    }
    void reset(size_t key)
    {
        size_t byte = key >> 5;
        size_t bit = key % 32;
        _vc[byte] &= ~(1 << bit);
    }
    bool Test(size_t key)
    {
        size_t byte = key >> 5;
        size_t bit = key % 32;
        if ((_vc[byte]) & (1 << bit))
            return true;
        return false;
    }
private:
    vector<int> _vc;
};

HashFun.h


template<class T> //各類哈希字符串轉換函數  
size_t BKDRHash(const char *str)
{
    register size_t hash = 0;
    while (size_t ch = (size_t)*str++)
    {
        hash = hash * 131 + ch;
    }
    return hash;
}

template<class T>
size_t SDBMHash(const char *str)
{
    register size_t hash = 0;
    while (size_t ch = (size_t)*str++)
    {
        hash = 65599 * hash + ch;
    }
    return hash;
}

template<class T>
size_t RSHash(const char * str)
{
    size_t hash = 0;
    size_t magic = 63689;
    while (size_t ch = (size_t)*str++)
    {
        hash = hash * magic + ch;
        magic *= 378551;
    }
    return hash;
}


template<class T>
size_t APHash(const char *str)
{
    register size_t hash = 0;
    size_t ch;
    for (long i = 0; ch = (size_t)*str++; i++)
    {
        if ((i & 1) == 0)
        {
            hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
        }
        else
        {
            hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
        }
    }
    return hash;
}


template<class T>
size_t JSHash(const char* str)
{
    if (!*str)
    {
        return 0;
    }
    size_t hash = 1315423911;
    while (size_t ch = (size_t)*str++)
    {
        hash ^= ((hash << 5) + ch + (hash >> 2));
    }
    return hash;
}

Bloom_Filter.h

#pragma once
#include"bitMap.hpp"
#include"HashFun.h"
#include<string>
template <typename T>
struct HashFun1
{
    size_t operator()(const T& str)
    {
        return  BKDRHash<T>(str.c_str());
    }
};
template <typename T>
struct HashFun2
{
    size_t operator()(const T& str)
    {
        return  SDBMHash<T>(str.c_str());
    }
};
template <typename T>
struct HashFun3
{
    size_t operator()(const T& str)
    {
        return  RSHash<T>(str.c_str());
    }
};
template <typename T>
struct HashFun4
{
    size_t operator()(const T& str)
    {
        return  APHash<T>(str.c_str());
    }
};
template <typename T>
struct HashFun5
{
    size_t operator()(const T& str)
    {
        return  JSHash<T>(str.c_str());
    }
};
template<typename T = string,
    typename HashFun1 = HashFun1<T>,
    typename HashFun2 = HashFun2<T>,
    typename HashFun3 = HashFun3<T>,
    typename HashFun4 = HashFun4<T>,
    typename HashFun5 = HashFun5<T>>
class Bloom_Filter
{
public:
    Bloom_Filter(int size)
    :_map(size)
    , _range(size)
    {}
    void set(const T& str)
    {
        _map.set(HashFun1()(str)%_range);
        _map.set(HashFun2()(str) % _range);
        _map.set(HashFun3()(str) % _range);
        _map.set(HashFun4()(str) % _range);
        _map.set(HashFun5()(str) % _range);
    }
    bool test(const T& str)
    {
        if (!_map.Test(HashFun1()(str) % _range))
            return false;
        if (!_map.Test(HashFun2()(str) % _range))
            return false;
        if (!_map.Test(HashFun3()(str) % _range))
            return false;
        if (!_map.Test(HashFun4()(str) % _range))
            return false;
        if (!_map.Test(HashFun5()(str) % _range))
            return false;
        return true;
    }
private:
    bitMap _map;
    size_t _range;
};

Bloom_Filter.cpp

#include"Bloom_Filter.h"
int main()
{
    Bloom_Filter<string> _bf(1024); 
    _bf.set("hjku");
    bool ret = _bf.test("hjku");
    ret = _bf.test("dfg");
    return 0;
}
  • 優點:一般判斷一個元素是不是在集合裏,我們需要將元素保存起來,在通過比較來判斷,這樣的話元素數量增大時我們需要很大的內存來存儲這些元素,並且檢索的速度也會越來越慢,布隆過濾器不需要存儲元素本身,並且採用哈希來確定元素的插入位置和查找元素,所以空間和時間效率都非常高,各個哈希函數之間沒有關係,方便硬件併發運行,而且不用存儲元素本身適合一些對保密有要求的場合。
  • 缺點:由於hash函數特性以及位圖數組長度有限,不同的對象可能在某些位上有重疊,這些位上的1未必是該元素之前設置的,有可能是別的元素所設置的,所以會造成一些誤判,即原本不在bloom filter中的一些元素也被判別在bloom filter中。誤算率就是它的一個缺點,並且隨着元素的增加,誤算率也會越來越高。由於元素存儲是由多個hash函數決定的,所以一般情況下無法從中刪除元素,我們很容易想到把位列陣變成整數數組,每插入一個元素相應的計數器加1,這樣刪除元素時將計數器減掉就可以了。然而要保證安全的刪除元素並非如此簡單。首先我們必須保證刪除的元素的確在布隆過濾器裏面. 這一點單憑這個過濾器是無法保證的。另外計數器迴繞也會造成問題。
  • 布隆過濾器的應用。
    Google Chrome瀏覽器使用Bloom filter識別惡意鏈接
    (能用較小的存儲空間表示較大的數據集合,簡單想就是把 每一個URL都可以映射成bit)
    並且誤判率在萬分之一以下。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章