手撸布隆过滤器

一个低配版BloomFilter

public class MyBloomFilter {
    // 后面hash函数会用到,用来生成不同的hash值,可以随便给,但别给奇数
    private final int[] ints = {6, 8, 16, 38, 58, 68};
    // 统计当前对象数量
    private Integer currentBeanCount = 0;
    // 你的布隆过滤器容量
    private int DEFAULT_SIZE = Integer.MAX_VALUE;
    // bit数组,用来存放结果
    private final BitSet bitSet = new BitSet(DEFAULT_SIZE);

    public MyBloomFilter() {
    }

    public MyBloomFilter(int size) {
        if (size > Integer.MAX_VALUE) throw new RuntimeException("size is too large");
        if (size <= (2 << 8)) throw new RuntimeException("size is too small");
        DEFAULT_SIZE = size;
    }
	
	// 获取当前过滤器的对象数量
    public Integer getCurrentBeanCount() {
        return currentBeanCount;
    }

    // 计算出key的hash值,并将对应下标置为1
    public void push(Object key) {
        Arrays.stream(ints).forEach(i -> bitSet.set(hash(key, i)));
        currentBeanCount++;
    }

    // 判断key是否存在,true不一定说明key存在,但是false一定说明不存在
    public boolean contain(Object key) {
        boolean result = true;
        for (int i : ints) {
            result = result && bitSet.get(hash(key, i));
        }
        return result;
    }

    // hash算法,借鉴了hashmap的算法,利用i对同个key生成一组不同的hash值
    private int hash(Object key, int i) {
        int h;
        int index = key == null ? 0 : (DEFAULT_SIZE - 1 - i) & ((h = key.hashCode()) ^ (h >>> 16));
        return index > 0 ? index : -index;
    }
}

它在用作判断对象 是否存在 时有误判率,误判率随着对象数量增加而增加
但是用作判断对象 是否不存在 时,没有误判率

一亿条数据去重

    public static void main(String[] args) {
        //实例化
        MyBloomFilter filter = new MyBloomFilter();
        for (int i = 0; i < 20; i++) {
            //push到BloomFilter
            getPersonList(500000).forEach(person -> filter.push(person));
        }
        //push一个确定的对象
        filter.push(getFixedPerson(now));
        //判断这个对象是否存在
        long start = System.currentTimeMillis();
        System.out.println(filter.contain(getFixedPerson(now)));
        long end = System.currentTimeMillis() - start;
        System.out.println("bloomFilter内对象数量:" + filter.getCurrentBeanCount());
        System.out.println("耗时(ms):" + end + ",消耗内存(M):" + (ObjectSizeCalculator.getObjectSize(filter) / (1024 * 1024)));
    }

原理

       就是通过对比hash算法计算出来的下标,但注意,是对比一组,而不是一次,一次hash结果只对应一个下标

       把同一个key进行多次hash运算,将hash出来的下标放入数组,数组默认全为0,放入元素后该下标就为1,后面判断是否存在元素的时候也是进行同样次数的hash运算,看下结果对应的所有下标是否全为1,若全为1,则代表该key可能存在,若存在不为1的,则说明该key一定不存在;

默认bit数组:[0,0,0,0,0,0]
比方说有个key计算出的一组hash下标是0,2,5
对应位bit数组:[1,0,1,0,0,1]
判断某个未知key是否存在时候,假设我们计算出来的下标是0,2,4
对应位数组:[1,0,1,0,1,0]
此时位数组内5对应下标值为0,而已知key位数组的5对应下标位1,说明这两个key一定不同

       相反,如果某个key计算出来的下标为[1,0,1,0,0,1],只能说这个key可能存在,因为这几个位置可能是其它key计算出来的


       摘自:https://blog.csdn.net/qq_33709582/article/details/122046773

上一篇:C# lib open source


下一篇:VGG_多个3×3卷积层可看作是大尺寸卷积层的分解