什么是布隆过滤器?——超详细解析【建议收藏】

news2024/12/24 21:22:57

目录

1、什么是布隆过滤器?

2、实现原理

2.1、回顾哈希函数

2.1.1、哈希函数概念

2.1.2、散列函数的基本特性:

2.2、布隆过滤器数据结构

3、特点

3.1、支持删除吗?

3.2、优点

3.3、缺点

3.4、误判率

4、如何选择哈希函数个数和布隆过滤器长度?

5、手动模拟实现布隆过滤器

整体代码:

5.1、添加元素

5.2、查询元素

5.3、测试:

 6、guava实现布隆过滤器

7、布隆过滤器适用场景


1、什么是布隆过滤器?

布隆过滤器本质上是一种数据结构,是一种巧妙的概率型数据结构,用来高效的插入和查询,是用来告诉使用者某样东西一定不存在或者可能存在。使用多个哈希函数,将一个数据映射到位图结构中。例:

不了解位图吗?看这篇文章: http://t.csdn.cn/M5vmC


2、实现原理

先来回顾哈希函数吧 ~

2.1、回顾哈希函数

2.1.1、哈希函数概念

        将任意的输入数据转换成特定的输出数据的函数,转换后的数据称为哈希值或哈希编码,也叫散列值。如图:

 

2.1.2、散列函数的基本特性:

  •  如果两个散列值是不相同的【同一函数】,那么这两个散列值的原始输入是不同的。这个特性是散列函数具有确定性的结果,具有这种性质的散列函数称为单向散列函数
  • 散列函数的输入和输出不是唯一对应的关系,如果两个散列值相同,两个输入值很可能是相通的,但也可能是不同的,这种情况称为“散列碰撞”。

当我们存储海量数据时,哈希的空间效率很低,当只有一个哈希函数时,很容易发生哈希碰撞~ 

2.2、布隆过滤器数据结构

布隆过滤器是一个由固定大小的二进制向量或者位图和一系列映射函数所组成的。

在初始状态下,对于一个长度为m的位数组,所有位置0,如下:

        当有变量被加入集合时,通过K个映射函数将这个变量映射成位图中的K个点,把它们置为1【举例中以3个映射函数为例】:

 

 查询某个变量的时候,只要这些对应的点是否是都是1:

  • 如果这些点有一个0,则被查询的变量一定不存在
  • 如果都是1,则被查询的变量可能存在

为什么说可能存在,而不是一定存在呢?

        那是因为映射函数本身就是散列函数,散列函数就是会有碰撞哒~


3、特点

3.1、支持删除吗?

布隆过滤器不能直接支持删除操作,因为在删除一个元素时,可能会影响其他元素

例:

         当我们要删除obj1时,需要将4处置0,而此时obj2的hash3也是映射到4处,就会出现后续的查询有问题~

实现删除方案:

将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素是给计数器加一,删除元素时,减一【通过占用几倍存储空间来增加删除操作】

此方案的缺点:

  • 无法确认元素是否真正在布隆过滤器中【误判】
  • 存在计数回绕【溢出】

3.2、优点

  • 增加和查询元素的时间复杂度为O(k)【k为哈希函数的个数】,与数据量大小无关
  • 哈希函数相互之间没有关系,方便硬件并行运算
  • 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有较大优势
  • 在能够承受一定误判时,布隆过滤器比其他数据结构有很大的空间优势
  • 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  • 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

3.3、缺点

  • 有误判率,即存在假阳性,即不能准确判断元素是否在集合中【补救:再建立一个白名单,存储可能会误判的数据】
  • 不能获取元素本身
  • 一般情况,不能从布隆过滤器中删除元素

3.4、误判率

布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的,因此误判的根源在于相同的 bit 位被多次映射且置 1。

这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位。


4、如何选择哈希函数个数和布隆过滤器长度?

需要使用,套公式即可 ~ 


5、手动模拟实现布隆过滤器

整体代码:

import java.util.BitSet;

class SimpleHash {

    public int cap;//当前容量
    public int seed;//随机

    public SimpleHash(int cap,int seed) {
        this.cap = cap;
        this.seed = seed;
    }

    //模仿库中哈希写哈希函数:
    //根据seed的不同,创建不同的哈希函数
    int hash(String key) {
        int h;
        return (key == null) ? 0 : (seed * (cap-1)) & ((h = key.hashCode()) ^ (h >>> 16));
    }

}
public class MyBloomFilter {
    //导入库中的位图
    public BitSet bitSet;

    //记录存储了多少数据
    public int usedSize;

    //随机种子
    public static final int[] seeds = {3,5,9,11,15,19,25,31};//这里面的数字是随便设置的

    public SimpleHash[] simpleHashes;

    public static final int SIZE = 1 << 20;//这个20是随意给的

    public MyBloomFilter() {
        bitSet = new BitSet(SIZE);
        simpleHashes = new SimpleHash[seeds.length];

        for(int i = 0;i<simpleHashes.length;i++) {
            simpleHashes[i] = new SimpleHash(SIZE,seeds[i]);
        }
    }

    /**
     * 添加数据 到布隆过滤器
     * @param val
     */
    public void add(String val) {
        //3个哈希函数,分别处理当前的数据
        //把他们都存储在位图中即可

    }

    /**
     * 是否包含val,会存在误判
     * @param val
     * @return
     */
    public boolean contains(String val) {

    }

}

补充上述代码空缺部分:

5.1、添加元素

    /**
     * 添加数据 到布隆过滤器
     * @param val
     */
    public void add(String val) {
        //3个哈希函数,分别处理当前的数据

        for (SimpleHash simpleHash : simpleHashes) {
            int index = simpleHash.hash(val);
            //把他们都存储在位图中即可
            bitSet.set(index);
        }
        usedSize ++;
    }

5.2、查询元素

    /**
     * 是否包含val,会存在误判
     * @param val
     * @return
     */
    public boolean contains(String val) {
        for (SimpleHash simpleHash : simpleHashes) {
            int index = simpleHash.hash(val);
            boolean flg = bitSet.get(index);
            if(!flg) {
                return false;
            }
        }
        return true;
    }

5.3、测试:

    //测试
    public static void main(String[] args) {
        MyBloomFilter myBloomFilter = new MyBloomFilter();
        myBloomFilter.add("baidu1");
        myBloomFilter.add("baidu2");
        myBloomFilter.add("tencent");

        System.out.println(myBloomFilter.contains("baidu1"));//true
        System.out.println(myBloomFilter.contains("haha"));//false
    }

 6、guava实现布隆过滤器

  • 创建一个maven项目
  • 导入依赖
  • 测试

 依赖:

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>

测试:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;


public class Test {
    private static int size = 1000000;//预计要插入多少数据

    private static double fpp = 0.01;//期望的误判率

    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

    public static void main(String[] args) {
        //插入数据
        for (int i = 0; i < 1000000; i++) {
            bloomFilter.put(i);
        }
        int count = 0;
        for (int i = 1000000; i < 2000000; i++) {
            if (bloomFilter.mightContain(i)) {
                count++;
                System.out.println(i + "误判了");
            }
        }
        System.out.println("总共的误判数:" + count);
    }
}

 测试结果:


7、布隆过滤器适用场景

  • 网页爬虫中对URL的去重,避免爬取相同的URL地址
  • 垃圾邮件过滤,从数十亿个垃圾邮件列表中判断邮箱是否是垃圾邮箱
  • 秒杀系统,查看用户是否重复购买
  • 数据库防止穿库。 Google Bigtable,HBase 和 Cassandra 以及 Postgresql 使用BloomFilter来减少不存在的行或列的磁盘查找。避免代价高昂的磁盘查找会大大提高数据库查询操作的性能。
  • 业务场景中判断用户是否阅读过某视频或文章,比如抖音或头条,当然会导致一定的误判,但不会让用户看到重复的内容。
  • 缓存宕机、缓存击穿场景,一般判断用户是否在缓存中,如果在则直接返回结果,不在则查询db,如果来一波冷数据,会导致缓存大量击穿,造成雪崩效应,这时候可以用布隆过滤器当缓存的索引,只有在布隆过滤器中,才去查询缓存,如果没查询到,则穿透到db。如果不在布隆器中,则直接返回。
  • WEB拦截器,如果相同请求则拦截,防止重复被攻击。用户第一次请求,将请求参数放入布隆过滤器中,当第二次请求时,先判断请求参数是否被布隆过滤器命中。可以提高缓存命中率。Squid 网页代理缓存服务器在 cache digests 中就使用了布隆过滤器。Google Chrome浏览器使用了布隆过滤器加速安全浏览服务
  • Venti 文档存储系统也采用布隆过滤器来检测先前存储的数据。
  • SPIN 模型检测器也使用布隆过滤器在大规模验证问题时跟踪可达状态空间。

好啦!!!我们下期再见咯~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3 机器学习之聚类

学习笔记自&#xff0c;慕课网 《Python3 入门人工智能》 https://coding.imooc.com/lesson/418.html#mid32716 分类问题 1. 无监督学习 机器学习的一种方法&#xff0c;没有给定事先标记过的训练示例&#xff0c;自动对输入的数据进行分类或分群 优点&#xff1a; 1&#xf…

今年十八,喜欢CTF-杂项

目录 前言 菜狗杯杂项签到 我吐了你随意 损坏的压缩包 misc4 misc5 前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;被吉师散养的职业混子 &#x1fad2;每日emo&am…

Rad Studio 11.2 安装 QuickBurro 7.21 中间件组件教程

背景 QuickBurro 官方网址&#xff1a;http://www.quickburro.org/ 系统环境&#xff1a;Rad Studio 11.2 安装其他的组件操作和这个一样的&#xff0c;同样可以参考 开始配置 先打开 Rad Studio 11&#xff0c;依次点击 File–Open Project… 然后找到你解压的 qbcn 目录下的…

React 环境搭建以及创建项目工程(二)

创建工程 首先创建一个工程 npx create-react-app weibo cd移动到当前创建的文件下 cd weibo 安装 React 路由 npm install react-router react-router-dom5.2.0 --save 安装 npm install 安依赖包 npm install antd --save npm install axios --save 安装less和less-…

PyCharm安装步骤

以64位的Windows10系统为例&#xff1a; 下载链接&#xff1a;Thank you for downloading PyCharm! 下载并打开安装包 在 Installation Options&#xff08;安装选项&#xff09;页面按下图所示勾选相应内容&#xff1a; 等待电脑自动安装完成 在PyCharm里编写程序 第1步&a…

【python】天平最少砝码设计

题目 有一架天平&#xff0c;砝码的种类和个数要你来设计。给定一个整数n&#xff0c;则待称重的物品的重量可能是 [1,n] 之间的整数&#xff0c;砝码可以放在左盘也可以放在右盘&#xff0c;要能称出所有 [1,n] 重量的物品&#xff0c;请问如何设计砝码的种类和个数&#xff…

Unreal UFUNCTION函数宏标记

BlueprintCallable,使C中的函数在蓝图中能被调用,新建C类CustomActor继承AActor,并分别声明public、protected、private方法:拖拽一个CustomActor到Map中,打开关卡蓝图,可以到无法在蓝图中调出C中的方法:我们为这三个方法添加BlueprintCallable标记:然后在蓝图中调用:可以发现,…

驱动程序开发:多点电容触摸屏

驱动程序开发&#xff1a;多点电容触摸屏一、编写驱动前的知识准备1、CST340触摸屏芯片寄存器2、CST340触摸屏的硬件原理图3、电容触摸屏驱动是由几种linux驱动框架组成的4、linux多点电容触摸的(Multi-touch&#xff0c;简称 MT)协议二、驱动程序的编写1、修改设备树2、驱动程…

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】&#x1f34e;一. Spring AOP&#x1f352;1.1 什么是Spring AOP&#x1f352;1.2 Spring AOP的作用&#x1f352;1.3 AOP的组成&#x1f349;1.3.1 切面&#xff08;Aspect&#xff09;&#x1f349;1.3.2 连接点…

大数据NiFi(十一):NiFi入门案例一

文章目录 NiFi入门案例一 一、配置“GetFile”处理器

Elastic-Job分布式任务调度

一.什么是任务调度 **任务调度&#xff1a;**是指系统为了自动完成特点任务&#xff0c;在约定的特定时刻去执行任务的过程。有了任务调度就不需要人力去实现&#xff0c;系统可以在某个时间自动执行任务。 二&#xff0c;任务调度的实现方式&#xff1a; 1.**多线程方式实现…

【博客579】netfilter network flow 和 routing decision的网络流处理交互关系

netfilter网络流转&#xff08;network flow&#xff09;与路由决策&#xff08;routing decision&#xff09;的网络流处理交互关系 1、场景&#xff1a; 我们可以通过iptables来基于netfilter机制下发我们的hook处理函数&#xff0c;那么我们平时iptables的四表五链与报文的…

JDBC简介

大家好&#xff0c;今天给大家分享jdbc 首先我们要知道什么是jdbc JDBC(Java DataBase Connectivity) &#xff1a;Java数据库连接技术&#xff1a;具体讲就是通过Java连接广泛的数据库&#xff0c;并对表中数据执行增、删、改、查等操作的技术 看它的架构图 或者看这个图…

flowable工作流架构分析

flowable工作流目录概述需求&#xff1a;设计思路实现思路分析1.复杂的状态的或者状态的维度增加的状的条件极为复杂2.工作流3.BPMN2.0协议4.协议的元素5.互斥网关包容性网关&#xff08;Inclusive Gateway&#xff09;参考资料和推荐阅读Survive by day and develop by night.…

车载以太网 - DoIP诊断消息处理逻辑 - 05

前面我们已经介绍了DoIP信息头部处理逻辑和路由激活处理,那根据DoIP报文的顺序,在路由激活处理完成后,接下来我们就需要发送真正的DoIP诊断信息了,那今天我们就来介绍下DoIP诊断消息的处理逻辑。 诊断消息处理逻辑 DoIP诊断报文结构: 上面表格对于DoIP诊断报文的…

Android 11 SystemUI(状态/导航栏)-图标按键的深浅色

概述 自 Android 5.0 版本&#xff0c;Android 带来了沉浸式系统 bar&#xff08;状态栏和导航栏&#xff09;&#xff0c;Android 的视觉效果进一步提高&#xff0c;各大 app 厂商也在大多数场景上使用沉浸式效果。6.0开始提供了View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR标志位&a…

MVC架构模式 | 使用银行转账的功能实现引出MVC架构模式

一、银行转账的功能实现数据库表的准备创建数据库表&#xff0c;主要包括三个字段&#xff1a;自增的id、账户名、账户余额不使用MVC架构模式完成账户转账首先写一个页面&#xff0c;写入转账的账户和金额&#xff1b;并发送post请求<% page contentType"text/html;cha…

【JavaEE】进入Web开发的世界-HTML

目录 一、HTML 1.1概念篇 1.2工具篇 1.2.1文本类型的标签 1.2.2多媒体标签 1.2.3超链接 1.2.4target 1.2.5表格相关的标签 1.2.6 列表标签 1.2.7表单标签 进入Web开发的世界&#xff0c;了解html、css、JavaScript的使用。 Web开发的核心&#xff1a;准备各式各样的资…

元壤:国内首家免费的数字藏品、DAO数字化营销SaaS平台

元壤&#xff1a;国内首家免费的数字藏品、DAO数字化营销SaaS平台 元壤是 Web3.0 时代 NFT 数字藏品与用户服务的数字化工具。元壤是中国企业数字资产化及数字藏品营销解决方案提供商。元壤致力于通过产品和服务,助力企业资产数字化,数字营销化,通过科技驱动数字商业变革,让数…

如何仿真MOS电容的电压-电容曲线?

一、原理 电容的阻抗为&#xff1a; 假设在电容两端施加频率为 f 的小信号电压 v &#xff0c;电容上流过的小信号电流为 i &#xff0c;那么三者有如下关系&#xff1a; 二、仿真 设置频率为1/2pi&#xff0c;这样算出来斜率即为1/C。设置f为0.159155 斜率就是1/C&#xff0c…