大数据排重算法-布隆算法(BloomFilter)

本文介绍了一种大数据排重算法——布隆过滤器,详细解析其工作原理及应用场景,如网页爬虫URL防重等,并提供了一个简单的Java实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前续:网页上已经有很多布隆过滤器很全的资料了,由于博主最近在做网页爬虫,遇到url防重问题,所以认真分析了布隆滤波器原理,也参考了相关博文。旨在给出不同人对其不同的理解,好给大家更全面的参考。

BloomFilter算法,是一种大数据排重算法。在一个数据量很大的集合里,能准确断定一个对象不在集合里;判断一个对象有可能在集合里,而且占用的空间不大。它不适合那种要求准确率很高的情况,零错误的场景。通过牺牲部分准确率达到高效利用空间的目的。

场景一:假如有一个很大的表,通过字段key查询数据,操作很重;业务方请求时,传过来的key有很大一部分是不存在的;这种不存在的key请求就会浪费我们的查询资源。针对这种情况,我们可以引人BloomFilter算法,在请求key查询之前,使用BloomFilter匹配。如果不存在,就不用去查询了(正确率百分之百);如果存在,走原来的查询流程(有可能不存在的key混进去了)。

场景二:假如有一个很大的表,通过字段key判断是否存在,操作很重,如果存在就做一些操作,不存在就加入表中;可容许一定的误判。对应这种情况,我们也可以引入BloomFilter算法,通过key查询表判断存在否的方式可换成BloomFilter算法。如果存在,我们执行以前的逻辑(有一定的误判,业务也允许一定的错误);如果不存在,也执行以前的逻辑。

 BloomFilter是由一个长度为n的bit数组S和k个hash算法组成。先使bit数组的初始值为0.
 添加值M:M经过k个hash算法计算后,得到:M1, M2 … Mk; 然后,使S[M1]=1,S[M2]=2... S[Mk]=1
 判断值Y:Y经过k个hash算法计算后,得到:Y1,Y2... Yk。 然后,判断S[Y1],S[Y2] … S[Yk] 是否都为1。如果有一个不为1,那这个Y就一定是不存在的,以前没添加过;如果都为1,那这个Y可能存在,也可能其他值添加后,影响了这次判断的结果。

 我们要做的是尽量降低正确判断的误判率,资料显示, 当 k = ln(2)* m/n 时(k是hash函数个数,m是bit数组的长度,n是加入值的个数),出错概率是最小的。 

当然,如果我们要移除值,怎么办呢?当前的结构是没法实现的,我们可以通过在加一个等长的数据,存放每个bit位设置为1的次数,设置一次加1,取消一次减一。

 package com.ljt.algorithm;

import java.util.BitSet;

/**
 * BloomFilter算法,是一种大数据排重算法。在一个数据量很大的集合里,能准确断定一个对象不在集合里;判断一个对象有可能在集合里,而且占用的空间不大。它不适合那种要求准确率很高的情况,零错误的场景。通过牺牲部分准确率达到高效利用空间的目的。
 * 
 * 场景一:假如有一个很大的表,通过字段key查询数据,操作很重;业务方请求时,传过来的key有很大一部分是不存在的;这种不存在的key请求就会浪费我们的查询资源。针对这种情况,我们可以引人BloomFilter算法,在请求key查询之前,使用BloomFilter匹配。如果不存在,就不用去查询了(正确率百分之百);如果存在,走原来的查询流程(有可能不存在的key混进去了)。
 * 
 * 场景二:假如有一个很大的表,通过字段key判断是否存在,操作很重,如果存在就做一些操作,不存在就加入表中;可容许一定的误判。对应这种情况,我们也可以引入BloomFilter算法,通过key查询表判断存在否的方式可换成BloomFilter算法。如果存在,我们执行以前的逻辑(有一定的误判,业务也允许一定的错误);如果不存在,也执行以前的逻辑。
 * 
 * BloomFilter是由一个长度为n的bit数组S和k个hash算法组成。先使bit数组的初始值为0.
 * 添加值M:M经过k个hash算法计算后,得到:M1, M2 … Mk; 然后,使S[M1]=1,S[M2]=2... S[Mk]=1
 * 判断值Y:Y经过k个hash算法计算后,得到:Y1,Y2... Yk。 然后,判断S[Y1],S[Y2] … S[Yk]
 * 是否都为1。如果有一个不为1,那这个Y就一定是不存在的,以前没添加过;如果都为1,那这个Y可能存在,也可能其他值添加后,影响了这次判断的结果。
 * 
 * 我们要做的是尽量降低正确判断的误判率,资料显示, 当 k = ln(2)* m/n
 * 时(k是hash函数个数,m是bit数组的长度,n是加入值的个数),出错概率是最小的。
 * 
 * 当然,如果我们要移除值,怎么办呢?当前的结构是没法实现的,我们可以通过在加一个等长的数据,存放每个bit位设置为1的次数,设置一次加1,取消一次减一。
 */
public class SimpleBloomFilter {
    public static final int BLOOMSIZE = 2 << 24; // 规定bloom的长度24bits
    public static final int[] seeds = { 3, 5, 7, 11, 13, 31, 37, 61, 131 }; // 8个hashset函数
    private BitSet bits = new BitSet(BLOOMSIZE); // 定义一个24位长的bit 所有位初始值都是false

    // 把字符串加到布隆滤波器中,简而言之就是把该字符串的相应hashcode映射到bits上
    public boolean add(String s) {
        if (s.equals("") || (s == null)) {
            return false;
        }
        for (int i = 0; i < seeds.length; i++) {
            HashCodeGen hcg = new HashCodeGen(seeds[i]);
            int codeGen = hcg.hashCodeGen(s);
            bits.set(codeGen, true);
        }
        return true;
    }

    // 判断该字符串是否存在
    public boolean contain(String s) throws Exception {
        if (s.equals("") || (s == null)) { // 输入的字符串需要控制
            throw new Exception("非法输入字符串");
        }
        boolean ret = true;
        for (int i = 0; i < seeds.length; i++) {
            HashCodeGen hcg = new HashCodeGen(seeds[i]);// 生成seeds长度的对象
            ret = ret && bits.get(hcg.hashCodeGen(s));
            if (ret == false)
                break;
        }
        return ret;
    }

    public static void main(String[] args) {
        SimpleBloomFilter bfn = new SimpleBloomFilter();

        bfn.add("www.baidu.com");
        try {
            System.out.println(bfn.contain("www.baidu.com.cn"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

class HashCodeGen {
    private int seed = 0;

    public HashCodeGen(int seed) {
        this.seed = seed;
    }

    // 生成hash码
    public int hashCodeGen(String s) {
        int hash = 0;
        for (int i = 0; i < s.length(); i++) {
            hash = hash * seed + s.charAt(i);
        }
        return (hash & 0x7ffffff);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ljtyxl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值