zoukankan      html  css  js  c++  java
  • 布隆过滤器

    什么是布隆过滤器

    • 布隆过滤器(Bloom Filter)是有布隆在 1970 年提出的。它实际上是由一个很长的二进制向量和一系列随机映射函数组成。布隆过滤器是用来检索一个元素是否在一个集合中。
      * 优点:空间效率和查询时间都远远超过一般算法,因为使用数组存入,同时使用二进制,占用空间小
      * 缺点:
      1. 有一定的误识别率
      2. 很难做删除操作

    原理

    对 Key 进行 n 个 hash 算法获取 n 个值,在比特数组中将这 k 个值三列后设定为1。查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该 Key 存在

    增删查

    • 增:经过多个 hash 函数,把
    • 删:

    说明

    布隆过滤器是一种数据结构,一种概率性的数据结果,它会告诉你“某样东西一定不存在或者可能存在”

    布隆过滤器是一个 bit 向量或者说 bit 数组,如下:

    现在,我们把 “AliPay” 给存储进去,存储过程:将要映射的值,使用多个不同的 hash 函数生产多个哈希值,然后每个生产的哈希值执行的 bit 置为1

    同样,现在我要存储另外一个值 “WechatPay” ,那么可能映射之后就是下面这样

    4 号位置的值,刚开始给 “AliPay” 了,后来 “WechatPay” 也在那里,这样的话,值不就给覆盖掉了嘛

    嗯,没错,是被覆盖掉了

    接下来,我们查询 “Ali” 那么查询之后,布隆过滤器可能会给你 “0,1,2” 的值, 结果呢 “2” 的位置是 0 ,说明没有任何值映射到这个位置上来,所以我们就可以判定数据库里面没有 “Ali” 这个值

    那查询 “AliPay” 的话,毫无疑问,肯定会返回给我 “1,4,6” ,那我们能说数据库里面一定有 “AliPay” 么?不能,因为 “1,4,6” 的值有可能被其他的值给覆盖到了,所以我们只能说,数据库里可能存在 “AliPay”

    这就是布隆过滤器说的"某个值一定不存在或者可能存在"

    布隆过滤器使用场景

    1. 针对缓存穿透,使用布隆过滤器,防止不存在的数据直接打到数据库上
    2. 去重:比如新闻推荐,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉已经存在的记录。如果使用 Mysql 类似的关系型数据库,需要进行大量的查询,并发量很大时,数据库压力很大。在用户浏览记录存入数据库时,把记录也保存一份到布隆过滤器,推送新闻的时候,通过布隆过滤器判断,推送内容存在就不推送了,不存在就推送。

    实际开发使用布隆过滤器

    直接采用 Guava 的 BloomFiler

    布隆过滤器实现

    1. MyBloomFilter.java
    import java.util.Arrays;
    import java.util.BitSet;
    
    /**
     * 布隆过滤器
     */
    public class MyBloomFilter {
        //布隆过滤器容量
        private static final int DEFAULT_SIZE = 2 << 28;
        // bit 数组,用来存放结果
        private static BitSet bitSet = new BitSet(DEFAULT_SIZE);
        // hash 函数会用到,用来生成不同的 hash 值,可随意设置
        private static final int[] ints = {1, 6, 16, 38, 58, 68};
    
        // hash 函数,借鉴了 hashmap 的扰动算法
        private int hash(Object key, int i) {
            int h;
            return key == null ? 0 : (i * (DEFAULT_SIZE - 1) & ((h = key.hashCode()) ^ (h >>> 16)));
        }
    
        // add 方法,计算出 key 的 hash 值,并将对应下标置为 true
        public void add(Object key) {
            Arrays.stream(ints).forEach(i -> bitSet.set(hash(key, i)));
        }
    
        // 判断 key 是否存在,true 不一定说明 key 存在,但是 false 一定说明不存在
        public boolean isContain(Object key) {
            boolean result = true;
            for (int i : ints) {
                // 短路与,只要有一个 bit 位为false,则返回false
                result = result && bitSet.get(hash(key, i));
            }
            return result;
        }
    }
    
    1. 测试数据
    public class MyBloomFilterTest {
        public static void main(String[] args) {
            MyBloomFilter bloomFilter = new MyBloomFilter();
            bloomFilter.add("张学友");
            bloomFilter.add("郭德纲");
            bloomFilter.add("刘德华");
            System.out.println(bloomFilter.isContain("张学友"));
            System.out.println(bloomFilter.isContain("郭德纲"));
            System.out.println(bloomFilter.isContain("刘德华"));
            System.out.println(bloomFilter.isContain("666"));
            System.out.println(bloomFilter.isContain("888"));
        }
    }
    

    测试结果:
    true
    true
    true
    false
    false

    参考:
    https://blog.csdn.net/qq_33709582/article/details/108407706
    https://mp.weixin.qq.com/s/SlfLgsfbvytxNS46fTFUdA

  • 相关阅读:
    ubuntu 安装(install) pwntcha[一个做"验证码识别"的开源程序]
    MySQL 二进制日志过滤
    MySQL 分区表各个分区的行数
    MySQL 表分区A
    MySQL show binglog event in 'log_name'
    MySQL、You are using safe update mode
    SQL 设计心得、逗号分隔列表
    MYSQL @、@@、@x
    SQL Server
    建设供内网访问的网站
  • 原文地址:https://www.cnblogs.com/liyiran/p/13832782.html
Copyright © 2011-2022 走看看