布隆过滤器(Bloom Filter)原理与应用——Mapreduce

布隆过滤器——初始状态    

 转自: 海量数据处理算法—Bloom Filter

假设Bloom Filter使用一个m比特的数组来保存信息,初始状态时,Bloom Filter是一个包含m位的位数组,每一位都置为0。


布隆过滤器——添加元素

将要添加的元素给k个哈希函数(Hash Function),也称之为散列函数, 得到对应于位数组上的k个位置,将这k个位置设为1。

现有S={x1, x2,…,xn}这样一个n个元素的集合,Bloom Filter使用k个相互独立的哈希函数(Hash Function),它们分别将集合中的每个元素映射到{1,…,m}的范围中。

增加任意一个元素x时候,我们使用k个哈希函数得到k个哈希值,然后将数组中对应的比特位设置为1。


布隆过滤器——查询元素

将要查询的元素给k个哈希函数,得到对应于位数组上的k个位置

如果k个位置有一个为0,则肯定不在集合中;如果k个位置全部为1,则可能在集合中。

False Positive的比率为   f  ,f 满足下列公式:


在给定m和n时,能够使f最小化的k值为:


此时给出的f为:


Hadoop中的 Bloom Filter   

1.  默认的Bloom Filter    转自:Hadoop Bloom Filter 使用

    BloomFilter filter =new BloomFilter(vectorSize, Hash, Hash.MURMUR_HASH); 
    Key  key  =new Key("hadoop".getBytes());
    filter.add(key);
    Key hb  = new Key("hbase".getBytes());
    boolean has  =filter.membershipTest(key);
    System.out.println(has);
    System.out.println(filter.membershipTest(hb));

2.  CountingBloomFilter   可以增加删除key

CountingBloomFilter filter =new CountingBloomFilter(vectorSize, Hash, Hash.MURMUR_HASH); 

3.  DynamicBloomFilter  过滤器长度可以扩容

DynamicBloomFilter   filter  =new DynamicBloomFilter(vectorSize, Hash, Hash.MURMUR_HASH, 1); 

代码:  

给定一个用户评论的列表,过滤掉大部分没有包含特定关键词的评论

public class TrainingBloomfilter {
    public static int getOptimalBloomFilterSize(int numRecords,  float falsePosRate) {
        int size = (int) (-numRecords * (float) Math.log(falsePosRate) / Math
                .pow(Math.log(2), 2));
        return size;
    }
 public static int getOptimalK(float numMembers, float vectorSize) {
        return (int) Math.round(vectorSize / numMembers * Math.log(2));
    }

。。。。。

public class BloomFilterDriver { 
    public static void main(String[] args) throws Exception {
        Path inputFile = new Path(args[0]);
        int numMembers = Integer.parseInt(args[1]);
        float falsePosRate = Float.parseFloat(args[2]);
        Path bfFile = new Path(args[3]);

        int vectorSize = getOptimalBloomFilterSize(numMembers, falsePosRate);
        int nbHash = getOptimalK(numMembers, vectorSize);
        BloomFilter filter = new BloomFilter(vectorSize, nbHash, Hash.MURMUR_HASH);

        String line = null;
        int numElements = 0;
        FileSystem fs = FileSystem.get(new Configuration());
        for (FileStatus status : fs.listStatus(inputFile)) {
        BufferedReader rdr = new BufferedReader(new InputStreamReader(new GZIPInputStream(fs.open(status.getPath()))));    
            while ((line = rdr.readLine()) != null) {
                filter.add(new Key(line.getBytes()));
                ++numElements;
            }
            rdr.close();
        }
        FSDataOutputStream strm = fs.create(bfFile);
        filter.write(strm);
        strm.flush();
        strm.close();
        System.exit(0);
    }
}

。。。。

public static class BloomFilteringMapper extends Mapper<Object, Text, Text, NullWritable> { 
    private BloomFilter filter = new BloomFilter();
 
    protected void setup(Context context) throws IOException,  InterruptedException {
        URI[] files = DistributedCache.getCacheFiles(context.getConfiguration());
        System.out.println("Reading Bloom filter from: "    + files[0].getPath());
        DataInputStream strm = new DataInputStream(new FileInputStream(files[0].getPath()));
        filter.readFields(strm);
        strm.close();
    }
    public void map(Object key, Text value, Context context)  throws IOException, InterruptedException {
        Map<String, String> parsed = transformXmlToMap(value.toString());

        String comment = parsed.get("Text");
        StringTokenizer tokenizer = new StringTokenizer(comment);
        while (tokenizer.hasMoreTokens()) {
            String word = tokenizer.nextToken();
            if (filter.membershipTest(new Key(word.getBytes()))) {
                context.write(value, NullWritable.get());
                break;
            }
        }
    }
}

 应用:

~  字处理软件中,需要检查一个英语单词是否拼写正确
~  在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上
~  在网络爬虫里,一个网址是否被访问过

~  yahoo, gmail等邮箱垃圾邮件过滤功能

    垃圾邮件过滤。(用哈希表实现的具体办法是将每一个 email地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email地址需要占用十六个字节。一亿个地址大约要 1.6GB,即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB的内存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解决同样的问题

方法: 

~  数组
~  链表
~  树、平衡二叉树、Trie
~  Map (红黑树)

~  哈希表





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值