布隆过滤器-详解及使用

news2024/11/16 10:31:17

一、什么是布隆过滤器

1、简介

布隆过滤器是一个很长的二进制向量和一系列随机映射函数。可以用于检索一个元素是否在一个集合中。。理解为SET集合。

布隆过滤器其内部维护了一个全为 0 的 bit 数组,需要说明的是,布隆过滤器有一个误判的概念,误判率越低,则数组越长,所占空间越大。误判率越高则数组越小,所占的空间多少。(关于误判后面会讲到)

布隆过滤器的优点:

  1. 时间复杂度低,增加和查询元素的时间复杂为O(N),(N为哈希函数的个数,通常情况比较小)
  2. 保密性强,布隆过滤器不存储元素本身
  3. 存储空间小,如果允许存在一定的误判,布隆过滤器是非常节省空间的(相比其他数据结构如Set集合)

布隆过滤器的缺点:

  1. 有点一定的误判率,但是可以通过调整参数来降低
  2. 无法获取元素本身
  3. 很难删除元素

2、使用场景

1. 数据去重:

  • 场景描述: 在一些需要对大量数据进行去重的场景,例如用户提交表单、数据同步等,布隆过滤器可以迅速判断某个数据是否已存在,避免重复插入。
  • 应用实例: 在用户提交表单时,使用布隆过滤器判断该用户是否已经提交过相同的数据,从而防止重复提交。

2. 缓存穿透问题的解决:

  • 场景描述:当缓存中不存在某个数据,而用户频繁查询该数据时,可能导致缓存穿透问题。布隆过滤器可以在缓存层之前迅速过滤掉不存在的数据,减轻数据库的压力。
  • 应用实例: 在缓存中存储热门商品的ID列表,并使用布隆过滤器判断某个商品ID是否存在于列表中,从而决定是否查询数据库获取数据。

3. 爬虫数据去重:

  • 场景描述: 在爬虫应用中,避免重复抓取相同的数据是一项关键任务。布隆过滤器可以帮助爬虫快速判断某个URL是否已经被抓取过。
  • 应用实例: 在爬虫系统中,使用布隆过滤器存储已抓取的URL,以避免重复请求同一URL。

4. 安全黑名单:

  • 场景描述: 在需要防范恶意攻击或恶意请求的场景中,布隆过滤器可以用于快速判断某个IP地址或请求是否在黑名单中。
  • 应用实例: 在Web应用中,使用布隆过滤器维护一份IP黑名单,快速拦截恶意请求。

5. URL访问记录:

  • 场景描述: 对于某些需要记录用户访问记录的应用,布隆过滤器可以用于判断某个URL是否已经被记录,避免重复记录。
  • 应用实例: 在网站访问日志记录中,使用布隆过滤器判断某个URL是否已经被记录,防止访问记录过于庞大。

6. 缓存预热:

  • 场景描述: 在系统启动时,通过布隆过滤器判断某些热门数据是否在缓存中,可以加速系统的启动过程。
  • 应用实例: 在SpringBoot应用启动时,使用布隆过滤器判断热门商品的ID是否在缓存中,并提前加载到缓存中,减少冷启动时的缓存穿透问题。

3、布隆过滤器的原理

3.1 数据结构

以Redis中的布隆过滤器实现为例,Redis中的布隆过滤器底层是一个大型位数组(二进制数组)+多个无偏hash函数。

  • 一个大型位数组(二进制数组):
    -
  • 多个无偏hash函数:无偏hash函数就是能把元素的hash值计算的比较均匀的hash函数,能使得计算后的元素下标比较均匀的映射到位数组中。

3.2 增加元素

往布隆过滤器增加元素,添加的key需要根据k个无偏hash函数计算得到多个hash值,然后对数组长度进行取模得到数组下标的位置,然后将对应数组下标的位置的值置为1

  • 通过k个无偏hash函数计算得到k个hash值
  • 依次取模数组长度,得到数组索引
  • 将计算得到的数组索引下标位置数据修改为1

例如,key = Liziba,无偏hash函数的个数k=3,分别为hash1、hash2、hash3。三个hash函数计算后得到三个数组下标值,并将其值修改为1.
如图所示:
在这里插入图片描述

3.3 查询元素

布隆过滤器最大的用处就在于判断某样东西一定不存在或者可能存在,而这个就是查询元素的结果。其查询元素的过程如下:

  • 通过k个无偏hash函数计算得到k个hash值
  • 依次取模数组长度,得到数组索引
  • 判断索引处的值是否全部为1,如果全部为1则存在(这种存在可能是误判),如果存在一个0则必定不存在

4、关于误判

假设,根据误判率,我们生成一个 10 位的 bit 数组,以及 2 个 hash 函数 f1 和 f2,如下图所示:生成的数组的位数 和 hash 函数的数量。这里我们不用去关心如何生成的,因为有数学论文进行验证。
在这里插入图片描述
然后我们输入一个集合,集合中包含 N1N2,我们通过计算 f1(N1) = 2,f2(N1) = 5,则将数组下标为 2 和下标为 5 的位置设置成 1,就得到了下图。

在这里插入图片描述

同理,我们再次进行计算 N2的值, f1(N2) = 3f2(N2) = 6。得到如下所示的图

在这里插入图片描述

这个时候,假设我们有第三个数 N3 过来了,需要判断 N3 是否在集合 [N1,N2] 中,需要做的操作就是,使用 f1f2 计算出数组中的地址

  • 若值恰巧都位于上图的红色位置,我们认为 N3在集合 [N1,N2] 中
    -若值有一个不位于上图的红色部分,我们认为N3不在集合 [N1,N2] 中

这就是布隆过滤器的计算原理。

二、使用

在 Java 中使用布隆过滤器,首先需要引入依赖,布隆过滤器拥有 Google 提供的一个开箱即用的组件,来帮助实现布隆过滤器。其实布隆过滤器的核心思想其实并不难,难的是在于如何设计随机映射函数,到底映射几次,二进制向量设置多少比较合适。

1、添加依赖

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>     
        <artifactId>guava</artifactId>      
        <version>22.0</version>
    </dependency>
</dependencies>

2、测试

    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);
    }

代码分析
上面的代码中,我们创建了一个布隆过滤器,其中有两个重要的参数,分别是我们要预计插入的数据和我们所期望的误判率,误判率率不能为 0 。

我们首先向布隆过滤器中插入 0 ~ 100万 条数据,然后在用 100万 ~ 200万的数据进行测试

最后输出结果,查看一下误判率

1999501误判了
1999567误判了
1999640误判了
1999697误判了
1999827误判了
1999942误判了
总共的误判数:10314

现在有 100万 不存在的数据,误判了 10314 次,通过计算可以得出误判率

10314 / 1000000 = 0.010314

和之前定义的误判率为 0.01 相差无几,这也说明了布隆过滤器在处理 Redis 缓存穿透问题上,也具有比较好的表现。

3、 springboot集成

创建布隆过滤器 Bean

在SpringBoot的Java配置类中,创建布隆过滤器的Bean,并注入相关配置。

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BloomFilterConfig {

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

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

    @Bean
    public BloomFilter<String> bloomFilter() {
        return BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), size , fpp );
    }
}

使用布隆过滤器

在你的服务类或控制器中,注入布隆过滤器的Bean,并使用它进行元素的判重。

package fun.bo.controller;

import com.google.common.hash.BloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/bloom-filter")
public class BloomFilterController {

    @Resource
    private BloomFilter<String> bloomFilter;

    @GetMapping("/add/{value}")
    public String addToBloomFilter(@PathVariable String value) {
        bloomFilter.put(value);
        return "Added to Bloom Filter: " + value;
    }

    @GetMapping("/contains/{value}")
    public String checkBloomFilter(@PathVariable String value) {
        boolean contains = bloomFilter.mightContain(value);
        return "Bloom Filter contains " + value + ": " + contains;
    }
}


这样,你就成功地将布隆过滤器整合到了SpringBoot项目中。请注意,具体的整合步骤可能会因使用的布隆过滤器库而有所不同,上述步骤仅供参考。在实际项目中,你还可以根据具体需求调整配置和使用方式。

在这里插入图片描述

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

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

相关文章

【全开源】宇鹿家政系统(FastAdmin+ThinkPHP+原生微信小程序)

&#xff1a;助力家政行业数字化升级 一、引言&#xff1a;家政服务的新篇章 随着移动互联网的普及和人们生活水平的提高&#xff0c;家政服务的需求日益增长。为了满足这一市场需求&#xff0c;并推动家政行业的数字化升级&#xff0c;我们特别推出了家政小程序系统源码。这…

代码随想录算法训练营第四十二天|62.不同路径、63. 不同路径 II

62.不同路径 文档讲解&#xff1a;代码随想录 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 记录每个格子的状态 二维矩阵-->二维dp数组 dp数组 题目是要求到达最后一个格子有多少种路径 所以dp[i,j]: 到达第(i,j)个格子有多少种路径 递推公式 到达一…

vue+three.js实现3d系统的搭建

1.首先node.js是12.22版本的&#xff0c;安装three.js可以参考这篇文章 直接用Threejs入门-安装教程_安装three.js-CSDN博客 直接在终端安装three.js即可 npm install --save three 在相同目录下安装vite构建工具 npm install --save-dev vite 在项目里面看package.json中…

1688 API接口介绍:开启您的电商新篇章

什么是1688 API接口&#xff1f; API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是一组协议和工具&#xff0c;用于定义不同的软件应用程序如何彼此交互。1688 API接口则是1688平台为商家提供的一套接口规范&#xff0c;允许商家…

浏览器提示网站不安全怎么办?有什么解决办法吗?

当你在浏览器中访问一个网站时&#xff0c;如果看到提示说该网站不安全&#xff0c;这通常是由于网站没有使用SSL证书或者SSL证书存在问题。SSL证书在这里扮演着非常关键的角色&#xff0c;下面我会详细解释它的作用以及如何解决这类不安全提示。 SSL证书的作用&#xff1a; 1…

德邦快递和德邦物流运费标准哪个更划算?怎样才能便宜的寄大件快递?

在寄大件包裹快递时&#xff0c;我们一般都知道选择德邦&#xff0c;那么德邦快递和德邦物流的收费标准哪个更划算呢&#xff1f;下面&#xff0c;让我们一起来了解德邦快递和德邦物流的收费标准&#xff0c;以及如何根据实际情况做出最佳选择。 首先了解快递费用构成 快递费用…

OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI(一)

引言 在Android中Java可以通过JNI 与C/C 通信&#xff0c;而在OpenHarmony 中前段语言目前是ETS&#xff0c;那么OpenHarmony中的 “JNI” 角色是什么呢&#xff1f; 一、NAPI概述 NAPI全称Native Application Programming Interface&#xff08;最新版的文档已经改为Node-A…

java医院管理系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的医院管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 医院管理系统的主要使用者分…

【IDEA】Redis可视化神器

在开发过程中&#xff0c;为了方便地管理 Redis 数据库&#xff0c;我们可能会使用一些数据库可视化插件。这些插件通常可以帮助你在 IDE 中直观地查看和管理 Redis 数据库&#xff0c;包括查看键值对、执行命令、监视数据库活动等。 IDEA作为IDE界的Jenkins&#xff0c;本身自…

软件项目管理 - 作业集合

软件项目管理 - 作业集合 作业一 1、项目与日常运作的主要区别有哪些&#xff1f; 项目&#xff1a;为提供一项独特产品、服务或成果所做的临时性努力 运作&#xff1a;连续不断周而复始的活动 项目是一次性的&#xff0c;日常运作是重复进行的&#xff1b; 项目是以目标为导…

Spring AOP基于动态代理的实现的 AOP

目录 代理什么是代理代理模式 静态代理动态代理JDK动态代理CGLIB动态代理Spring AOP使用的是哪种代理&#xff1f; 代理 什么是代理 生活中的代理 房产中介 &#xff1a; 房屋进行租赁时&#xff0c;卖方会把房子授权给中介&#xff0c;由中介代理带客户看房&#xff0c;商谈…

线段树例题

目录 1.Sequence 2.Peach Conference 3.Permutation Subsequence 1.Sequence 题目描述&#xff1a; Given an array a consisting of n integers, on which you are to perform m operations of two types. 1.Given two integers x,y, replace the number of index x with n…

httpsok-v1.12.0支持LB证书自动部署

&#x1f525;httpsok-v1.12.0支持LB证书自动部署 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具&#xff0c;基于全新的设计理念&#xff0c;专为 Nginx 、OpenResty 服务器设计。已服务众多中小企业&#xff0c;稳定、安全、可靠。 一行命令&#xff0c;一分钟轻松搞…

console.log——NPM库

前期回顾 Vue3 TS 项目实战 - 后台管理系统 - 按钮权限_vue3ts后台管理-CSDN博客 目录 &#x1f6a9;不使用NPM插件的方式 第一步&#xff1a;创建log函数-源码 第二步&#xff1a;注册到window上 第三步&#xff1a;扩展Window接口 第四步&#xff1a;确保类型文件…

leetcode 530.二叉搜索树的最小绝对差 、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

leetcode 530.二叉搜索树的最小绝对差 、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先 leetcode 530.二叉搜索树的最小绝对差 题目链接&#xff1a;https://leetcode.cn/problems/maximum-binary-tree/description/ 题目&#xff1a; 给你一个二叉搜索树的根节点 r…

【Qt】Qt定时器类QTimer

在进行窗口程序的处理过程中, 经常要周期性的执行某些操作, 或者制作一些动画效果&#xff0c;看似比较复杂的问题使用定时器就可以完美的解决这些问题&#xff0c; Qt中提供了两种定时器方式一种是使用Qt中的事件处理函数这个在后续章节会给大家做细致的讲解&#xff0c;本节主…

常用目标检测预训练模型大小及准确度比较

目标检测是计算机视觉领域中的一项重要任务&#xff0c;旨在检测和定位图像或者视频中的目标对象。当人类观看图像或视频时&#xff0c;我们可以在瞬间识别和定位感兴趣的对象。目标检测的目标是使用计算机复制这种智能。 近年来&#xff0c;目标检测网络的发展日益成熟&#…

设计模式基础——设计原则介绍

1.概述 ​ 对于面向对象软件系统的设计而言&#xff0c;如何同时提高一个软件系统的可维护性、可复用性、可拓展性是面向对象设计需要解决的核心问题之一。面向对象设计原则应运而生&#xff0c;这些原则你会在设计模式中找到它们的影子&#xff0c;也是设计模式的基础。往往判…

力扣刷题--1528. 重新排列字符串【简单】

题目描述 给你一个字符串 s 和一个 长度相同 的整数数组 indices 。 请你重新排列字符串 s &#xff0c;其中第 i 个字符需要移动到 indices[i] 指示的位置。 返回重新排列后的字符串。 示例 1&#xff1a; 输入&#xff1a;s “codeleet”, indices [4,5,6,7,0,2,1,3] 输…

OpenMV的VisionBoard视觉识别开发板学习记录

此篇博客仅用于对VisionBoard的开发板的学习研究记录&#xff0c;没有教学内容。 一、资料来源 开发板资料链接 开发板环境搭建手册 开发板视频教程 板子的资料网站 openmv官方的网站 目录 一、资料来源二、针对 VisionBoard的目标识别和定位总结1. 目标识别功能1.1 物体检测…