Java布隆过滤器的原理和实现分析

目录
  • 前言
  • 1. 预备知识
    • 1.1 哈希函数
  • 2. 布隆过滤器
    • 2.1 概念
    • 2.2 实现原理
    • 2.3 步骤
    • 2.4 实现

前言

数组、链表、树等数据结构会存储元素的内容,一旦数据量过大,消耗的内存也会呈现线性增长

所以布隆过滤器是为了解决数据量大的一种数据结构

讲述布隆过滤器的时候需要了解一些预备的知识点:比如哈希函数

1. 预备知识

1.1 哈希函数

哈希函数指将哈希表中元素的关键键值映射为元素存储位置的函数

一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较“的基础上,查找的效率依赖于查找过程中所进行的比较次数。 理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应

具体其构造器的方法有:

直接定址法、数字分析法、平方取中法、折叠法、除留余数法等

解决其冲突的方法有:

拉链法、多哈希法、开放地址法、建域法等

2. 布隆过滤器

2.1 概念

它实际上是一个很长的二进制向量和一系列随机映射函数。(位数组和哈希函数)

布隆过滤器可以用于检索一个元素是否在一个集合中。

它的优点是空间效率和查询时间都比一般的算法要好的多(更加高效,存储空间小)

缺点是有一定的误识别率和删除困难

2.2 实现原理

之所以要用布隆过滤器,是因为HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,而且数据大了之后不可能一次性

比如存储码农研究僧这个值,通过三个哈希函数,算得三个哈希值,存放在3个位置中(位数组)

之后判定查询码农博士僧的时候,发现这三个值只要有1个没有为1,就是没存储到,也就是没在集合中

但是如果存储的值很多,再去查找的时候,可能会出现一定的误判率,导致本身没在集合中,但位数组却都是1的情况

具体如何选择上面所说的位数组长度和哈希函数的个数呢

布隆器如果过小,导致很多位置都很快是1,误判率就很很高,如果布隆器过长,误判率会越小

哈希函数的个数如果过少,其速度慢,误判率也高,如果哈希函数的个数过多,其位1的速度加快,导致布隆过滤器的效率越低

2.3 步骤

添加元素的具体的步骤是

将添加的元素给k个哈希函数算出对应位数组上的k个位置,将这k个位置设为1

查询元素的具体步骤是

将要查询的元素给k个哈希函数算出对应于位数组上的k个位置,如果k个位置有一个为0,则肯定不在集合中。如果k个位置全部为1,则可能在集合中

在计数布隆过滤器中,进行删除的前提是必须保证,值一定存在。因此单通过布隆过滤器无法保证值一定存在。如果通过其他的方法确认值存在后进行删除,则不能保证该值在后续布隆过滤器查询时一定返回不存在,因为该值相对应的位置并不一定为零。但确实可以一定概率上优化查询的效率。因此不能说计数布隆过滤器支持删除,应该说计数布隆过滤器提供了实现删除的可能

2.4 实现

public class MyBloomFilter {

    /**
     * 一个长度为10 亿的比特位
     */
    private static final int DEFAULT_SIZE = 256 << 22;

    /**
     * 为了降低错误率,使用加法hash算法,所以定义一个8个元素的质数数组
     */
    private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};

    /**
     * 相当于构建 8 个不同的hash算法
     */
    private static HashFunction[] functions = new HashFunction[seeds.length];

    /**
     * 初始化布隆过滤器的 bitmap
     */
    private static BitSet bitset = new BitSet(DEFAULT_SIZE);

    /**
     * 添加数据
     *
     * @param value 需要加入的值
     */
    public static void add(String value) {
        if (value != null) {
            for (HashFunction f : functions) {
                //计算 hash 值并修改 bitmap 中相应位置为 true
                bitset.set(f.hash(value), true);
            }
        }
    }

    /**
     * 判断相应元素是否存在
     * @param value 需要判断的元素
     * @return 结果
     */
    public static boolean contains(String value) {
        if (value == null) {
            return false;
        }
        boolean ret = true;
        for (HashFunction f : functions) {
            ret = bitset.get(f.hash(value));
            //一个 hash 函数返回 false 则跳出循环
            if (!ret) {
                break;
            }
        }
        return ret;
    }

    /**
     * 测试。。。
     */
    public static void main(String[] args) {

        for (int i = 0; i < seeds.length; i++) {
            functions[i] = new HashFunction(DEFAULT_SIZE, seeds[i]);
        }

        // 添加1亿数据
        for (int i = 0; i < 100000000; i++) {
            add(String.valueOf(i));
        }
        String id = "123456789";
        add(id);

        System.out.println(contains(id));   // true
        System.out.println("" + contains("234567890"));  //false
    }
}

class HashFunction {

    private int size;
    private int seed;

    public HashFunction(int size, int seed) {
        this.size = size;
        this.seed = seed;
    }

    public int hash(String value) {
        int result = 0;
        int len = value.length();
        for (int i = 0; i < len; i++) {
            result = seed * result + value.charAt(i);
        }
        int r = (size - 1) & result;
        return (size - 1) & result;
    }
}

到此这篇关于Java布隆过滤器的原理和实现分析的文章就介绍到这了,更多相关Java布隆过滤器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java的布隆过滤器你了解吗

    目录 BitMap 布隆过滤器 运用场景 传统数据结构的不足 实现原理 误判现象 实现 Redis 的 bitmap RedisBloom Guava 的 BloomFilter Redisson 解决缓存穿透 总结 BitMap 现代计算机用二进制(bit,位)作为信息的基础单位,1 个字节等于 8 位,例如big字符串是由 3 个字节组成,但实际在计算机存储时将其用二进制表示,big分别对应的 ASCII 码分别是 98.105.103,对应的二进制分别是 01100010.01101001

  • 什么是Java布隆过滤器?如何使用你知道吗

    目录 一.布隆过滤器简介 二.布隆过滤器的结构 三.布隆过滤器应用 四.布隆过滤器的优缺点 五.布隆过滤器实战 六.总结 Redis缓存穿透可以通过布隆过滤器进行解决,那么什么是布隆过滤器呢?请往下看. 通常你判断某个元素是否存在用的是什么? 很多人想到的是HashMap. 确实可以将值映射到 HashMap 的 Key,然后可以在 O(1) 的时间复杂度内返回结果,效率奇高.但是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,而一旦你的值很多

  • 布隆过滤器的原理以及java 简单实现

    一.布隆过滤器 布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难. 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路.但是随着集合中元素的增加,我们需要的存储空间越来越大.同时检索

  • Java实现布隆过滤器的方法步骤

    前言 记得前段时间的文章么?redis使用位图法记录在线用户的状态,还是需要自己实现一个IM在线用户状态的记录,今天来讲讲另一方案,布隆过滤器 布隆过滤器的作用是加快判定一个元素是否在集合中出现的方法.因为其主要是过滤掉了大部分元素间的精确匹配,故称为过滤器. 布隆过滤器 在日常生活工作,我们会经常遇到这的场景,从一个Excel里面检索一个信息在不在Excel表中,还记得被CTRL+F支配的恐惧么,不扯了,软件开发中,一般会使用散列表来实现,Hash Table也叫哈希表,哈希表的优点是快速准确

  • JAVA实现较完善的布隆过滤器的示例代码

    布隆过滤器是可以用于判断一个元素是不是在一个集合里,并且相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势.布隆过滤器存储空间和插入/查询时间都是常数.但是它也是拥有一定的缺点:布隆过滤器是有一定的误识别率以及删除困难的.本文中给出的布隆过滤器的实现,基本满足了日常使用所需要的功能. 0 0 0 0 0 0 0 0 0 0 先简单来说一下布隆过滤器.其实现方法就是:利用内存中一个长度为M的位数组B并初始化里面的所有位都为0,如下面的表格所示: 然后我们根据H个不同的散列函数,对传进来

  • 布隆过滤器(Bloom Filter)的Java实现方法

    布隆过滤器原理很简单:就是把一个字符串哈希成一个整数key,然后选取一个很长的比特序列,开始都是0,在key把此位置的0变为1:下次进来一个字符串,哈希之后的值key,如果在此比特位上的值也是1,那么就说明这个字符串存在了. 如果按照上面的做法,那就和哈希算法没有什么区别了,哈希算法还有重复的呢. 布隆过滤器是将一个字符串哈希成多个key,我还是按照书上的说吧. 先建立一个16亿二进制常量,然后将这16亿个二进制位全部置0.对于每个字符串,用8个不同的随机产生器(F1,F2,.....,F8)产

  • Java布隆过滤器的原理和实现分析

    目录 前言 1. 预备知识 1.1 哈希函数 2. 布隆过滤器 2.1 概念 2.2 实现原理 2.3 步骤 2.4 实现 前言 数组.链表.树等数据结构会存储元素的内容,一旦数据量过大,消耗的内存也会呈现线性增长 所以布隆过滤器是为了解决数据量大的一种数据结构 讲述布隆过滤器的时候需要了解一些预备的知识点:比如哈希函数 1. 预备知识 1.1 哈希函数 哈希函数指将哈希表中元素的关键键值映射为元素存储位置的函数 一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定

  • python实现布隆过滤器及原理解析

    在学习redis过程中提到一个缓存击穿的问题, 书中参考的解决方案之一是使用布隆过滤器, 那么就有必要来了解一下什么是布隆过滤器.在参考了许多博客之后, 写个总结记录一下. 一.布隆过滤器简介 什么是布隆过滤器? 本质上布隆过滤器( BloomFilter )是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 "某样东西一定不存在或者可能存在". 相比于传统的 Set.Map 等数据结构,它更高效

  • 通过实例解析布隆过滤器工作原理及实例

    布隆过滤器 布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 "一定不存在或者可能存在". 相比于传统的 List.Set.Map 等数据结构,它更高效.占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的. 布隆过滤器的工作原理 假设一个长度为m的bit类型的数组,即数组中每个位置只占一个bit,每个bit只有两种状态:0,1,所有bit的初始状态都为0. 再假设一共有k个哈

  • Java的优先队列PriorityQueue原理及实例分析

    这篇文章主要介绍了Java的优先队列PriorityQueue原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.优先队列概述 优先队列PriorityQueue是Queue接口的实现,可以对其中元素进行排序, 可以放基本数据类型的包装类(如:Integer,Long等)或自定义的类 对于基本数据类型的包装器类,优先队列中元素默认排列顺序是升序排列 但对于自己定义的类来说,需要自己定义比较器 二.常用方法 peek()//返回队首元素

  • java类和对象原理与用法分析

    本文实例讲述了java类和对象原理与用法.分享给大家供大家参考,具体如下: 面向对象编程OOP 类:相似对象的集合. 对象 对象:实体.一切可以被描述的事物. 属性:特征. 方法:动作,行为. 类和对象的区别 [1]类时抽象的,对象是具体的. [2]类是一个模板,创建出来的对象具备共同的属性和方法. [3]类是一种数据烈性.引用数据类型. 语法 public classs 类名{ //定义属性部分 属性1的类型 属性1: 属性2的类型 属性2: ... 属性3的类型 属性n; //定义方法部分

  • Java类的继承原理与用法分析

    本文实例讲述了Java类的继承.分享给大家供大家参考,具体如下: 为什么要继承? 观察两个类的成员组成 提取相同的属性和方法 宠物是父类,狗和金鱼是子类.子类具有父类的属性和方法. 继承定义 是使用已存在的类作为基础建立新类的技术. 单一继承:只有一个父类. 父类可以叫做基类.超类.子类可以叫做派生类. 继承注意事项 子类可以继承父类中的成员(属性和方法). 但是需要注意: 1.private的成员不能继承 2.子类和父类不在同一个程序包,使用默认访问权限的成员不能继承 3.构造器不能继承. 继

  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理

    目录 布隆过滤器的原理 在 Python 中使用布隆过滤器 1.标准布隆过滤器. 2.计数布隆过滤器. 3.标准扩容布隆过滤器. 4.计数扩容布隆过滤器. Redis 中使用布隆过滤器 最后的话 在开发软件时,我们经常需要判断一个元素是否在一个集合中,比如,如何判断单词的拼写是否错误(判断单词是否在已知的字典中):在网络爬虫里,如何确认一个网址是否已经爬取过:反垃圾邮件系统中,如何判断一个邮件地址是否为垃圾邮件地址等等. 如果这些作为面试题那就很有区分度了,初级工程师就会说,把全部的元素都存在

  • Redis实现布隆过滤器的方法及原理

    布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难. 本文将介绍布隆过滤器的原理以及Redis如何实现布隆过滤器. 应用场景 1.50亿个电话号码,现有10万个电话号码,如何判断这10万个是否已经存在在50亿个之中?(可能方案:数据库,set, hyperloglog) 2.新闻客户端看新闻时,它会不

随机推荐