`

布隆过滤器方法及实现(Bloom Filter)

阅读更多
在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素时,将它和集合中的元素直接比较即可。一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来了。比如说,一个象 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。如果用哈希表,每存储一亿个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个 email 地址对应成一个八字节的信息指纹 googlechinablog.com/2006/08/blog-post.html,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要 1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的。

今天,我们介绍一种称作布隆过滤器的数学工具,它只需要哈希表 1/8 到 1/4 的大小就能解决同样的问题。

布隆过滤器是由巴顿.布隆于一九七零年提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。我们通过上面的例子来说明起工作原理。

假定我们存储一亿个电子邮件地址,我们先建立一个十六亿二进制(比特),即两亿字节的向量,然后将这十六亿个二进制全部设置为零。对于每一个电子邮件地址 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 对应的八个二进制一定是一。这样在遇到任何在黑名单中的电子邮件地址,我们都能准确地发现。

布隆过滤器决不会漏掉任何一个在黑名单中的可疑地址。但是,它有一条不足之处。也就是它有极小的可能将一个不在黑名单中的电子邮件地址判定为在黑名单中,因为有可能某个好的邮件地址正巧对应个八个都被设置成一的二进制位。好在这种可能性很小。我们把它称为误识概率。在上面的例子中,误识概率在万分之一以下。

布隆过滤器的好处在于快速,省空间。但是有一定的误识别率。常见的补救办法是在建立一个小的白名单,存储那些可能别误判的邮件地址。

====================================================================
具体实现:
import java.util.BitSet;

public class bloomFilter implements java.io.Serializable {

    private int defaultSize = 5000 << 10000;
    private int basic = defaultSize -1;
    private String key = null;
    private BitSet bits = new BitSet(defaultSize);

    public bloomFilter(){
    }

    public bloomFilter(String key){
        this.key = key;
    }

    private int[] lrandom(String key){
        int[] randomsum = new int[8];
        int random1 = hashCode(key,1);
        int random2 = hashCode(key,2);
        int random3 = hashCode(key,3);
        int random4 = hashCode(key,4);
        int random5 = hashCode(key,5);
        int random6 = hashCode(key,6);
        int random7 = hashCode(key,7);
        int random8 = hashCode(key,8);
        randomsum[0] = random1;
        randomsum[1] = random2;
        randomsum[2] = random3;
        randomsum[3] = random4;
        randomsum[4] = random5;
        randomsum[5] = random6;
        randomsum[6] = random7;
        randomsum[7] = random8;
        return randomsum;
    }

    private int[] sameLrandom(String key){
        int[] randomsum = new int[8];
        int random1 = hashCode(key,1);
        int random2 = hashCode(key,1);
        int random3 = hashCode(key,1);
        int random4 = hashCode(key,1);
        int random5 = hashCode(key,1);
        int random6 = hashCode(key,1);
        int random7 = hashCode(key,1);
        int random8 = hashCode(key,1);
        randomsum[0] = random1;
        randomsum[1] = random2;
        randomsum[2] = random3;
        randomsum[3] = random4;
        randomsum[4] = random5;
        randomsum[5] = random6;
        randomsum[6] = random7;
        randomsum[7] = random8;
        return randomsum;
    }


    public void add(String key){
        if(exist(key)){
            System.out.println("已经包含("+key+")");
            return;
        }
        int keyCode[] = lrandom(key);
        getBits().set(keyCode[0]);
        getBits().set(keyCode[1]);
        getBits().set(keyCode[2]);
        getBits().set(keyCode[3]);
        getBits().set(keyCode[4]);
        getBits().set(keyCode[5]);
        getBits().set(keyCode[6]);
        getBits().set(keyCode[7]);
    }

    public boolean exist(String key){
        int keyCode[] = lrandom(key);
        if(getBits().get(keyCode[0])&&
                getBits().get(keyCode[1])
                &&getBits().get(keyCode[2])
                &&getBits().get(keyCode[3])
                &&getBits().get(keyCode[4])
                &&getBits().get(keyCode[5])
                &&getBits().get(keyCode[6])
                &&getBits().get(keyCode[7])){
            return true;
        }
        return false;
    }

    private boolean set0(String key){
        if(exist(key)){
            int keyCode[] = lrandom(key);
            getBits().clear(keyCode[0]);
            getBits().clear(keyCode[1]);
            getBits().clear(keyCode[2]);
            getBits().clear(keyCode[3]);
            getBits().clear(keyCode[4]);
            getBits().clear(keyCode[5]);
            getBits().clear(keyCode[6]);
            getBits().clear(keyCode[7]);
            return true;
        }
        return false;
    }

    public int hashCode(String key,int Q){
        int h = 0;
        int off = 0;
        char val[] = key.toCharArray();
        int len = key.length();
        for (int i = 0; i < len; i++) {
            h = (30 + Q) * h + val[off++];
        }
        return changeInteger(h);
    }

    private int changeInteger(int h) {
        return basic & h;
    }

    //碰撞测试
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        bloomFilter f = new bloomFilter();
        int err=0;
        for(int i=1;i<2100000000;i++) {
            if(f.exist(String.valueOf(i))) {
                err++;
            }else {
                f.add(String.valueOf(i));
            }
            System.out.println("Error "+i+" :"+err/i*100+"%");
        }        
         f.add(String.valueOf(23482734));
        //f.add("http://www.agrilink.cn/");
        //System.out.println(f.exist("http://www.agrilink.cn/"));
        //f.set0("http://www.agrilink.cn/");
        //System.out.println(f.exist("http://www.agrilink.cn/"));
    }

    /**
     * @return the bits
     */
    public BitSet getBits() {
        return bits;
    }

    /**
     * @param bits the bits to set
     */
    public void setBits(BitSet bits) {
        this.bits = bits;
    }

}
分享到:
评论

相关推荐

    bloom filter(C#版自制布隆过滤器)

    C# 版本的布隆过滤器实现了这一概念,通过使用八种不同的哈希函数来提高准确性和减少冲突。 布隆过滤器的基本原理是将所有可能存在的元素映射到一个固定大小的位数组(bit array)上。这个位数组最初全部设置为0。...

    布隆过滤器C源码-bloomfilter.rar

    例如,`bf_create(size_t capacity, uint8_t num_hashes)`用于创建一个布隆过滤器,`bf_insert(bloom_filter* filter, const void* item)`用于插入元素,`bf_query(bloom_filter* filter, const void* item)`用于...

    Go-布隆过滤器的一个Go实现参考bloomfilter.js

    `bloomfilter.js`可能是JavaScript版本的布隆过滤器实现,而"Go-布隆过滤器的一个Go实现参考bloomfilter.js"则表明该Go版本的实现是借鉴了JavaScript版本的设计思路或代码结构。 Go实现布隆过滤器的关键组件包括: ...

    布隆过滤器-BloomFilter

    在Java中,实现布隆过滤器可以使用开源库如Guava或者自定义实现。例如,`BloomFilter.java`和`MyBloomFilter.java`可能是两个不同的实现版本。自定义实现通常包括以下几个关键部分: 1. **位数组(Bit Array)**:...

    java实现的布隆过滤器算法

    在提供的压缩包文件`Bloom Filter`中,可能包含了具体的Java实现代码,你可以通过阅读和分析这些代码来深入理解布隆过滤器的工作原理和Java实现细节。此外,还可以通过测试不同参数组合下的性能,进一步了解布隆过滤...

    布隆过滤器BloomFilters的一个简单Java库

    布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素是否可能在一个集合中。在Java开发中,特别是在处理大数据、内存限制或需要快速查询是否存在某个元素的场景下,布隆过滤器是一个...

    布隆过滤器之C++实现

    C++实现的布隆过滤器,其中使用到的bitset也是自己简单实现的一个BitContainer。可以处理千万条到亿条记录的存在性判断。做成dll可以在很多场合使用,如自己写爬虫,要判断一个url是否已经访问过,判断一个单词是否...

    bloom filter布隆过滤器学习资料大全

    布隆过滤器(Bloom Filter)是一种空间效率极高...通过这个“bloom filter布隆过滤器学习资料大全”,你可以深入研究布隆过滤器的理论、算法实现以及在不同场景下的应用实例,提升对这一重要数据结构的理解和应用能力。

    【技术分享】Bloomfilter布隆过滤器.pptx

    Redisson是一个Java客户端,它不仅支持Redis的各种功能,还包含了布隆过滤器的实现。通过使用Redisson,用户可以在分布式环境中利用布隆过滤器,提高系统的可扩展性和效率。 总的来说,布隆过滤器是一种在空间效率...

    Go-一个简单的golang布隆过滤器

    - `Intersection(other *BloomFilter)`: 计算两个布隆过滤器的交集,创建一个新的布隆过滤器,只保留同时存在于两个过滤器中的元素的位。 4. **优化策略**: - **位数组大小**:位数组的大小直接影响误判率,需要...

    硬核 - Redis 布隆(Bloom Filter)过滤器原理与实战.doc

    * 邮件过滤,使用布隆过滤器实现邮件黑名单过滤 * 爬虫爬过的网站过滤,爬过的网站不再爬取 * 推荐过的新闻不再推荐 * 去重问题,例如在明日头条APP中,推荐给用户的内容不会重复 Redis集成布隆过滤器需要使用Redis...

    布隆过滤器(利用布隆过滤器实现文字的嵌入和查找功能)

    布隆过滤器,大家学过数据结构的应该都清楚,一般的字典树要实现嵌入和查找都内存的消耗非常大,布隆过滤器有BloomFilter,string, BKDRHash, APHash, DJBHash&gt; bf五个参数你要查找的元素个数,查找元素类型,三个...

    Bloom_filter_(C).zip_bloom_bloom filter_c++布隆_布隆过滤器

    这个压缩包文件"Bloom_filter_(C).zip"包含了一个C++版本的布隆过滤器实现,它具有简单易学、易用的特点。 布隆过滤器的基本原理是通过多个哈希函数将元素映射到一个固定大小的位数组中。这些哈希函数是独立且随机...

    布隆过滤器的实现,以及测试用例,简单易懂并做了一些注释

    下面将详细介绍布隆过滤器的原理、实现及测试用例。 ### 布隆过滤器原理 1. **基本结构**:布隆过滤器是一个很长的二进制数组和几个独立的哈希函数。数组初始全为0,哈希函数是随机且独立的。 2. **插入操作**:...

    布隆过滤器python库

    在Python中,有多个库实现了布隆过滤器,其中一个就是我们这里提到的"python-bloomfilter-master"。 这个Python库提供了对布隆过滤器的简单接口,使得开发者可以方便地在项目中应用布隆过滤器。安装过程非常直观,...

    介绍Bloom Filter(布隆过滤器)原理、实现及具体应用

    布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素是否可能在一个集合中。它可能会误判,但不会漏判,即可能存在假阳性(False Positive),但绝不会有假阴性(False Negative)。...

    布隆过滤器(bloom filter)及php和redis实现布隆过滤器的方法

    在PHP和Redis中实现布隆过滤器,可以利用PHP的扩展库,如BloomFilter库,或者直接在Redis中使用BF.ADD、BF.MEMBERS和BF.EXISTS等命令操作布隆过滤器。Redis的布隆过滤器模块提供了方便的操作接口,能够在分布式环境...

    Java版本的BloomFilter (布隆过滤器)

    **布隆过滤器(Bloom Filter)**是一种空间效率极高的概率型数据结构,用于测试一个元素是否在一个集合中。由Burton Howard Bloom在1970年提出,主要用于节省存储空间,尤其在大数据场景下,它能有效地解决大规模...

    Cuckoo过滤器:实际上比 Bloom 更好_Go语言_代码_相关文件_下载

    Cuckoo 过滤器是近似集合成员查询的布隆过滤器替代品。虽然 Bloom 过滤器是众所周知的节省空间的数据结构,可以服务于“如果项目 x 在一个集合中?”之类的查询,但它们不支持删除。它们启用删除的差异(如计算 ...

    Ruby 中的 BloomFilter原生计数过滤器 + Redis 计数,非计数过滤器.zip

    Ruby 中的 BloomFilter原生计数过滤器 + Redis 计数/非计数过滤器Ruby 中的 BloomFilter原生(MRI/C)计数布隆过滤器Redis 支持的 getbit/setbit 非计数布隆过滤器Redis 支持的基于集合的计数 (+TTL) 布隆过滤器布隆...

Global site tag (gtag.js) - Google Analytics