布隆过滤器(海量数据找重复)

1. 布隆过滤器

它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难

布隆过滤器是与哈希算法是相关的,是工业实践上常用的算法,之前我们使用HashMap或者HashSet来查找重复的话也是可以的,但是对于在数据量比较大的情况下去查询那么速度就比较慢了,这个时候对于大的数据量来进行检索使用布隆过滤查找速度就比较快

2. 布隆过滤的思路:

先把已知的字符串先存储到位图中,比如位图的长度是100,那么对应着0~99个位置,这些数字对应的位置可以使用二进制的0或者1来表示

然后对于已知的字符串我们都通过若干个的哈希函数计算出哈希值,然后再把哈希值取位图的长度使哈希值落在位图的范围之中,这里,把哈希值对应位上的二进制数字置为1

存进去之已知的字符串之后那么我们就可以得到已知字符串的位图了

查询某个字符串是否在这个集合之中那么我们也是通过同样的方法,通过同样的若干个哈希函数经过计算检测对应的位图上的二进制数字是否为1,假如不是1那么这个字符串肯定不在这里面,因为之前的字符串对应的位图上的二进制位没有一个与当前的字符串进行匹配

假如检测到当前字符串的经过哈希函数计算出来的哈希值对应位图上都为1,那么这个时候可以大体上判断当前的字符串很有可能存在于这个集合之中,为什么呢?因为之前的好几个字符串经过哈希函数映射到位图上的二进制位为1那么有可能是几个字符串公共映射得到的位图上的二进制位数为1的结果,所以不能够与当前字符串进行匹配,所以只能判断当前字符串很有可能存在而不是一定存在,存在一定的误判率和误识别率

扫描二维码关注公众号,回复: 4709491 查看本文章

下面使用md5算法计算出哈希值并在对应的位图上置1,我们也可以使用其他的哈希函数计算出哈希值比如直接取余法,乘法这些,使用任何的哈希算法计算出来的哈希值对于检索的结果是没有影响的,只是检索的效率会有所不同

并且这里使用到了BigInteger类用来处理生成的比较大的数字

3. 具体的代码如下

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    //位图的长度
    public static final int NUM_SLOTS = 1024 * 1024 * 8;
    //哈希函数的个数
    public static final int NUM_HASH  = 8;
    //初始化位图
    private static BigInteger bits = new BigInteger("0"); 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        List<String> list = new ArrayList<String>();
        list.add("sddadsdaddsewwe");
        list.add("ddsdgsysahdsdys");
        list.add("eqtesdetwdghdsf");
        list.add("fhsjdfsdjfdhhgd");
        for(int i = 0; i < list.size(); i++){
            addElement(list.get(i));
        }
        System.out.println(check("ddadsdaddsewwe"));
        System.out.println(check("eqtesdetwdghdsf"));
        System.out.println(check("sfasga"));
        System.out.println(check("fhsjdfsdjfdhhgd"));
        sc.close();
    }

    private static void addElement(String string) {
        for(int i = 0; i < NUM_HASH; i++){
            int bit = hash(string, i);
            if(!bits.testBit(bit)){
                //左移将对应位图上的位置为1
                bits = bits.or(new BigInteger("1").shiftLeft(bit));
            }
        }
    }

    private static int hash(String message, int index) {
        message += index;
        try {
            MessageDigest md5 = MessageDigest.getInstance("md5");
            byte bytes[] = message.getBytes();
            md5.update(bytes);
            byte bits[] = md5.digest();
            BigInteger bi = new BigInteger(bits);
            return Math.abs(bi.intValue()) % NUM_SLOTS;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return -1;
    }
    
    private static boolean check(String string) {
        //使用与填充位图的方法一致检查对应位上是否为一
        for(int i = 0; i < NUM_HASH; i++){
            int index = hash(string, i);
            if(!bits.testBit(index)){
                return false;
            }
        }
        return true;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/84890546