Java实现布隆过滤器

一、介绍

 

1.描述

 

标识阶段

1.定义一个位的数组

2.使用多个hash函数计算hash值并取模

3.将每个hash函数的取模的结果所对应的标志位置位1

 

过滤阶段

1.使用多个hash函数计算要查询数据的hash值并取模

2.在位数组中寻找,多个值对应的多个为是否全是1,如果有一个不是1就说明不存在该值

 

2.使用场景

解决缓存穿透问题、网页黑名单过滤、垃圾邮件过滤等

 

3.布隆过滤器的误差

因为布隆过滤器的自身特点,可能会存在误差。当布隆过滤器的返回值为false时(不存在),说明这个数据一定不存在,布隆过滤器中的值为true时,有不存在的可能,这就产生了误差。

但我们可以通过下面的公式规定布隆过滤器的大小 和 hash函数的个数  来设定误差在我们可以接受的范围中

 

布隆过滤器的大小m公式: 其中p是失误率  n是数据的数量

公式1:

m=-\frac{n*\ln p}{\ln 2^{2}}

如果我们的数据量是n=100亿,失误率p=0.01%,通过公式1就能够得到m的值 

 

哈希函数的个数k公式:                                      

k=\ ln2*\frac{m}{n}

通过公式1,得到了m的值,就可以进一步计算,hash函数的个数。

 


 

二、实现

 

1.关键词

几个自定义的hash函数

一个位数组:Java.util包的BitSet类 或者 redis的bitmap

2.Java 实现

(1).通过bitset实现

 

import java.util.BitSet;

public class BloomFilter {

    //bloomFilter大小
    private static final int SIZE = 1<<24;

    //bitset初始化
    private static final BitSet bitset=new BitSet();

    //    计算hash值的辅助数组
    static final int[] seeds= {2, 3, 5, 7, 11, 13, 17, 19};

    //获取hash值
    public static int getHash(String data,int seed){
        int hash = 0;
        char arrChar[] = data.toCharArray();
        if (arrChar.length>0){
            for (int i = 0;i<arrChar.length;i++){
                hash = hash*seed+arrChar[i];//自定义hash算法
            }
        }
        return hash&(SIZE-1);
    }

    //  过滤  查找是否存在
    public static boolean isExist(String data){
        if(data==null&&data.length()==0){
            return false;
        }
        boolean res = true;
        for (int i = 0;i<seeds.length;i++){
            int index = getHash(data,seeds[i]);
            res&=bitset.get(index);//与运算,只要有有一个位置为null就false
        }
        return res;
    }
    //    标识  bitset置位 
    public static void add(String data){
        for (int i = 0;i<seeds.length;i++){
            int  hash = getHash(data,seeds[i]);
            bitset.set(hash,true);
        }

    }

    public static void main(String[] args) {
        System.out.println(isExist("111111"));//false
        add("111111");
        System.out.println(isExist("111111"));//true

        System.out.println(isExist("1111112"));//false
        add("1111112");
        System.out.println(isExist("1111112"));//true


    }
}

 

(2).通过redis 的 bitmap来实现

我是在在自己之前的一个springBoot项目中实现的。但是其实只要是该项目能操作redis就可以实现。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.BitSet;

@Service
public class BloomFilterRedisBitmap {

    @Autowired
    private RedisTemplate redisTemplate;
    //bloomFilter大小
    private static final int SIZE = 1 << 24;

    // 计算hash值的辅助数组
    private static final BitSet bitset = new BitSet();

    // hash函数,一个数组
    static final int[] seeds = {2, 3, 5, 7, 11, 13, 17, 19};

    public int getHash(String data, int seed) {
        int hash = 0;
        char arrChar[] = data.toCharArray();
        if (arrChar.length > 0) {
            for (int i = 0; i < arrChar.length; i++) {
                hash = hash * seed + arrChar[i];//自定义hash算法
            }
        }
        return hash & (SIZE - 1);
    }

    //   过滤 isExist
    public boolean isExist(String data) {
        if (data == null && data.length() == 0) {
            return false;
        }
        boolean res = true;
        for (int i = 0; i < seeds.length; i++) {
            int index = getHash(data, seeds[i]);
            //通过与运算,判断多个index位是否为1,只要有一个位是0 res 就是false
            res &= redisTemplate.opsForValue().getBit("hashKey", index);
        }
        return res;
    }

    //标识  置位
    public void add(String data) {
        for (int i = 0; i < seeds.length; i++) {
            int hash = getHash(data, seeds[i]);
            redisTemplate.opsForValue().setBit("hashKey", hash, true);
        }
    }
}

 

参考:

1.《程序员代码面试指南》左程云

2.https://www.cnblogs.com/zhenlingcn/p/8231786.html

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值