• BitMap再再体验之布隆过滤器


    前言

    还是从一个问题出发,如果需要判断一个元素是否存在应该用什么数据结构?

    比较常用的是HashMap, 我们回到BitMap初体验中的那个问题,给你一台 4G 内存的机器,一组 20 亿个元素(这个元素有可能是字符串,也有可能是一个对象),你怎么判断一个元素是否存在?这个时候我们就需要用到一种数据结构-布隆过滤器。

    实际中的业务场景:redis 的缓存穿透

    什么是布隆过滤器

    布隆过滤器本质上是一种比较巧妙的概率型数据结构,它可以告诉你某个元素一定不存在或者有可能存在

    优势和缺点

    优势:
    相比于HashMap, 它更高效,占用的空间更小

    缺点:
    它的返回结果是概率性的,不是确切的

    实现原理

    当插入一个元素时,将该元素分别输入k个哈希函数,产生k个哈希值,将这些哈希值存到BitMap中。

    当需要查询一个元素时,同样将该元素分别输入k个哈希函数,得到k个哈希值,然后判断这k个哈希值是否都存在。如果有一个哈希值不存在,则说明这个元素一定不存在;如果这k个哈希值都存在,则说明这个元素可能存在(有可能哈希冲突)。

    代码

    首先定义hash函数

    interface HashFunction<T> {
        int hash(T t);
    }
    
    class DefaultHashFunction<T> implements HashFunction<T> {
    
        @Override
        public int hash(T t) {
            return t == null ? 0 : t.hashCode();
        }
    }
    
    class StringHashFunction implements HashFunction<String> {
    
        @Override
        public int hash(String str) {
            if (str == null) {
                return 0;
            }
    
            int hash = 0;
            char[] chars = str.toCharArray();
    
            for (int i = 0; i < chars.length; i++) {
                hash = chars[i] + (hash << 6) + (hash << 16) - hash;
            }
    
            return hash;
        }
    }
    

    构造布隆过滤器

    class BloomFilter {
    
        private BitSet bitSet;
        private int DEFAULT_SIZE = 1 << 30;
        private List<HashFunction<String>> hfs;
    
        public BloomFilter() {
            bitSet = new BitSet(DEFAULT_SIZE);
            hfs = new ArrayList<HashFunction<String>>() {
                {
                    add(new DefaultHashFunction<>());
                    add(new StringHashFunction());
                }
            };
        }
    
        public void add(String value) {
            if (value != null) {
                for (HashFunction<String> hf : hfs) {
                    int hash = hf.hash(value);
                    hash = hash < 0 ? Math.abs(hash) : hash;
                    bitSet.set(hash);
                }
            }
        }
    
        public boolean contains(String value) {
            if (value == null) {
                return false;
            }
    
            for (HashFunction hf : hfs) {
                int hash = hf.hash(value);
                hash = hash < 0 ? Math.abs(hash) : hash;
    
                if (!bitSet.get(hash)) {
                    return false;
                }
            }
    
            return true;
        }
    }
    

    main 方法

    public class Demo {
        public static void main(String[] args) {
    
            BloomFilter bf = new BloomFilter();
            bf.add("boy");
            bf.add("girl");
            bf.add("mike");
            bf.add("jane");
    
            System.out.println(bf.contains("robot"));
            System.out.println(bf.contains("boy"));
    
        }
    }
    
  • 相关阅读:
    Excel标题与索引的对应关系
    拼接LINQ动态表达式
    根据输入的模型属性表达式获取名称
    如何将页面的<br/>在Excel中正确换行
    针对VM从挂机-启动后,docker相关服务的无法使用问题!
    NIO(三):Selector选择器
    NIO(二):Channel通道
    Netty(一):netty的入门使用。
    设计模式(五):原型模式
    NIO(一):Buffer缓冲区
  • 原文地址:https://www.cnblogs.com/lwmp/p/13640118.html
Copyright © 2020-2023  润新知