当前位置: 首页 > news >正文

布隆过滤器的使用

布隆过滤器简介

Bloom Filter(布隆过滤器)是一种多哈希函数映射的快速查找算法。它是一种空间高效的概率型数据结构,通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。

布隆过滤器的优势在于,利用很少的空间可以做到精确率较高,空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。为什么不允许删除元素呢:删除意味着需要将对应的 k 个 bits 位置设置为 0,其中有可能是其他元素对应的位。

哈希表与布隆过滤器

哈希表也能用于判断元素是否在集合中,但是Bloom Filter只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。Bloom Filter可以插入元素,但是不可以删除已有元素。集合中的元素越多,误报率越大,但是不会漏报。

应用场景

布隆过滤器的用处就是,能够在节省存储空间的情况下迅速判断一个元素是否在一个集合中。主要有如下几个典型使用场景:

  • 网页爬虫对URL的去重,避免爬取相同的URL地址;
  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;
  • 缓存击穿,将已存在的缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。
  • 黑白名单的过滤

原理

如果想判断一个元素是不是在一个集合中,一般想到的方法是暂存数据,然后查找判定是否存在集合中。这种方法在数据量比较小的情况下适用,但是几个中元素较多的时候,检索速度就会越来越慢。

可以利用Bitmap:只要检查对应点是不是1就可以知道集合中有没有这个数。Bloom filter可以看做是对bitmap的扩展。只是使用多个hash映射函数,从而减低hash发生冲突的概率。可以发现由于有hash的介入,布隆过滤器整体上是一种非常概率的数据结构,存在一定的误判率。所以有这样的特性:key命中了布隆过滤器,代表key可能在布隆过滤器中、key没有命中布隆过滤器,代表key一定不在布隆过滤器中。

在Go 中比较常用的是:https://github.com/bits-and-blooms/bloom,我们可以通过分析这个开源的项目来看下布隆过滤器的实现原理

例子

package mainimport ("fmt""github.com/bits-and-blooms/bitset"bloom "github.com/bits-and-blooms/bloom/v3"
)func main() {filter := bloom.NewWithEstimates(1000000, 0.01)filter.Add([]byte("a"))if filter.Test([]byte("a")) {fmt.Println("true")return}fmt.Println("false")
}

数据结构

type BloomFilter struct {m uintk uintb *bitset.BitSet
}// 这个才是 BloomFilter 真正的底层结构,就是一个 []uint64
type BitSet struct {length uintset    []uint64
}// 将元素添加到 布隆过滤器 里面
// Add data to the Bloom Filter. Returns the filter (allows chaining)
func (f *BloomFilter) Add(data []byte) *BloomFilter {h := baseHashes(data)for i := uint(0); i < f.k; i++ {f.b.Set(f.location(h, i))}return f
}

可以简单理解成下面这张图,元素1,6,9 经过 hash 函数之后存在了数组中,在Bloom Filters 可视化网站 可以看到动态视频。然后判断存不存在只需要判断hash 之后的元素对应的数组位置是不是都等于1

在这里插入图片描述

问题

布隆过滤器的容量及误判率该如何设定
  • 假设布隆过滤器容量为 n,过滤器误判率为 p, qps 为 x,一次请求对布隆过滤器的访问次数为 g,则极限 qps 场景下每秒对布隆过滤器的访问次数为 xg,那每秒可能会有 xg*p 的请求到 数据源中;假设我们的数据源的请求 qps限制 为 y,那么误判率 p 的估计取值为 y / (x*g)
  • 知道了容量和误判率之后,我们就可以通过:https://hur.st/bloomfilter/n=100000000&p=0.0002&m=&k= 大致预估出 布隆过滤器 的大小

在这里插入图片描述

如何更新布隆过滤器

因为布隆过滤器不能够删除,所以我们只能定时或者手动更新布隆过滤器

布隆过滤器 Redis 大Key问题

在 n= 1 亿,p=0.0002的数据下,布隆过滤器大概在 211.33MiB,这个时候我们存在redis 上,就会造成 redis 大key 问题,有可能会引起redis 的慢查询,拖挂 redis。

我们可以定时生成布隆过滤器讲结果存储在 DB 或者对象存储中,由每一个服务的实例定时去拉取生成的最新布隆过滤器数据。

Redis布隆过滤器

bitmap

在刚刚我们提到,布隆过滤器的核心数据结构为bitmap, 在Redis上也支持bitmap,其实就是对 string 的每一位进行操作。由此我们也可以得出,用 Redis的bitmap实现的布隆过滤器可以存储最大的数据量为:512x1024x1024x8 = 4294967296,42亿。

我们可以通过 SETBIT 来设置 bit的值,GETBIT 来获取 bit位的值

127.0.0.1:6379> SETBIT mykey 7 1
(integer) 0
127.0.0.1:6379> GETBIT mykey 7
(integer) 1
127.0.0.1:6379> SETBIT mykey 7 0
(integer) 1
127.0.0.1:6379> GETBIT mykey 7
(integer) 0
127.0.0.1:6379>

所以通过Redis bitmap来实现布隆过滤器需要做三件事情:

  • k 次散列函数计算出 k 个位点。
  • 插入时将位数组中 k 个位点的值设置为 1。
  • 查询时根据 1 的计算结果判断 k 位点是否全部为 1,否则表示该元素一定不存在

Bloom Filter

我们也可以通过安装 Redis 的插件:https://github.com/RedisBloom/RedisBloom,这个插件包含了很多数据类型。Bloom filter(布隆过滤器), Cuckoo filter(布谷鸟过滤器), Count-min sketch(频率算法), Top-K, t-digest(近似百分位算法)

在Redis中的操作
bloom filter定义

BF.RESERVE {key} {error_rate} {capacity}
使用给定的期望错误率和初始容量创建空的Bloom过滤器(如果不存在的话)。如果打算向Bloom过滤器中添加许多项,则此命令非常有用,否则只能使用BF.ADD 添加项。
初始容量和错误率将决定过滤器的性能和内存使用情况。一般来说,错误率越小(即对误差的容忍度越低),每个过滤器条目的空间消耗就越大。

bloom filter基本操作

BF.ADD {key} {item}

单条添加元素
向Bloom filter添加一个元素,如果该key不存在,则创建该key(过滤器)。
如果项是新插入的,则为“1”;如果项以前可能存在,则为“0”。

BF.MADD {key} {item} [item…]

批量添加元素
布尔数(整数)的数组。返回值为0或1的范围的数据,这取决于是否将相应的输入元素新添加到过滤器中,或者是否已经存在。

BF.EXISTS {key} {item}

判断单个元素是否存在
如果存在,返回1,否则返回0

BF.MEXISTS {key} {item} [item…]

判断多个元素是否存在

其他相关的命令可以在这里查询到:https://redis.io/commands/?name=bf

127.0.0.1:6379> BF.ADD bfKey 1
(integer) 1
127.0.0.1:6379> BF.ADD bfKey foo
(integer) 1
127.0.0.1:6379> BF.EXISTS bfKey 4
(integer) 0
127.0.0.1:6379> BF.EXISTS bfKey 4
(integer) 0
127.0.0.1:6379> BF.EXISTS bfKey 1
(integer) 1
127.0.0.1:6379> BF.EXISTS bfKey foo
(integer) 1
127.0.0.1:6379>

布谷鸟过滤器

为了解决布隆过滤器中不能删除,且存在误判的缺点,本文引入了一种新的哈希算法——cuckoo filter,它既可以确保该元素存在的必然性,又可以在不违背此前提下删除任意元素,仅仅比bitmap牺牲了微量空间效率。

原理

最简单的布谷鸟哈希结构是一维数组结构,会有两个 hash 算法将新来的元素映射到数组的两个位置。如果两个位置中有一个位置为空,那么就可以将元素直接放进去。但是如果这两个位置都满了,它就不得不「鸠占鹊巢」,随机踢走一个,然后自己霸占了这个位置。

  • 使用两个哈希函数 h1(x) 、 h2(x) 和两个哈希桶 T1、T2 。
  • 插入元素 x:
    • 如果 T1[h1(x)] 、T2[h2(x)] 有一个为空,则插入;两者都空,随便选一个插入。
    • 如果 T1[h1(x)] 、T2[h2(x)] 都满,则随便选择其中一个(设为 y ),将其踢出,插入 x。
    • 重复上述过程,插入元素 y。
  • 如果插入时,踢出次数过多,则说明哈希桶满了。则进行扩容、ReHash 后,再次插入。
  • 查询元素 x:
    • 读取 T1[h1(x)] 、T2[h2(x)] 和 x 比对即可
      可以通过这个Cuckoo Filter 可视化网站观察到。

其他

  • 布谷鸟哈希
  • 布谷鸟过滤器
  • 布谷鸟过滤器实现

相关文章:

布隆过滤器的使用

布隆过滤器简介 Bloom Filter(布隆过滤器)是一种多哈希函数映射的快速查找算法。它是一种空间高效的概率型数据结构&#xff0c;通常应用在一些需要快速判断某个元素是否属于集合&#xff0c;但是并不严格要求100%正确的场合。 布隆过滤器的优势在于&#xff0c;利用很少的空…...

Web开发-单例模式

目录 单例模式介绍代码实现单例模式 单例模式介绍 单例模式是一种创建型设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。单例模式可以通过private属性实现。通过将类的构造函数设为private&#xff0c;可以防止类在外部被实例化。单例模式通…...

MySQL:温备份和恢复-mysqldump (4)

介绍 温备&#xff1a;同样是在数据库运行的时候进行备份的&#xff0c;但对当前数据库的操作会产生影响。&#xff08;只可以读操作&#xff0c;不可以写操作&#xff09; 温备份的优点&#xff1a; 1.可在表空间或数据文件级备份&#xff0c;备份时间短。 2.备份时数据库依然…...

【力扣每日一题】2023.10.8 股票价格波动

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题是程序设计题&#xff0c;要我们实现一个类&#xff0c;一共是四个功能&#xff0c;第一个是给一个时间戳和价格&#xff0c;表示该…...

Linux隐藏文件或文件夹

在Linux中&#xff0c;以点&#xff08;.&#xff09;开头的文件或文件夹是隐藏文件或隐藏文件夹。要创建一个隐藏文件或文件夹&#xff0c;可以使用以下命令&#xff1a; 创建隐藏文件&#xff1a; touch .filename这将在当前目录下创建一个名为 “.filename” 的隐藏文件。…...

leetcode - 365周赛

一&#xff0c;2873.有序三元组中的最大值 I ​ 该题的数据范围小&#xff0c;直接遍历&#xff1a; class Solution {public long maximumTripletValue(int[] nums) {int n nums.length;long ans 0;for(int i0; i<n-2; i){for(int ji1; j<n-1; j){for(int kj1; k<…...

为什么mac上有的软件删除不掉?

对于Mac用户来说&#xff0c;软件卸载通常是一个相对简单的过程。然而&#xff0c;有时你可能会发现某些软件似乎“顽固不化”&#xff0c;即使按照常规方式尝试卸载&#xff0c;也依然存在于你的电脑上。这到底是为什么呢&#xff1f;本文将探讨这一问题的可能原因。 1.卸载失…...

【vue3】wacth监听,监听ref定义的数据,监听reactive定义的数据,详解踩坑点

假期第二篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 之前已经记录了一篇【vue3基础知识点-computed和watch】 今天在学习的过程中发现&#xff0c;之前记录的这一篇果然是很基础的&#xff0c;很多东西都讲的不够…...

跨境电商如何通过软文建立品牌形象?

在全球产业链结构重塑后的今天&#xff0c;越来越多的企业意识到想要可持续发展&#xff0c;就需要在建立品牌形象&#xff0c;在用户心中留下深刻印象&#xff0c;那么应该如何有效建立品牌形象呢&#xff1f;可以利用软文来打造品牌形象&#xff0c;接下来媒介盒子就告诉大家…...

我做了一个简易P图(参数图)分析软件

P图(即参数图&#xff0c;Parameter Diagram)&#xff0c;是一个结构化的工具&#xff0c;帮助大家对产品更好地进行分析。 典型P图格式 P图最好是和FMEA软件联动起来&#xff0c;如国可工软的FMEA软件有P图分析这个功能。 单纯的P图分析软件很少&#xff0c;为了方便做P图分…...

209.Flink(四):状态,按键分区,算子状态,状态后端。容错机制,检查点,保存点。状态一致性。flink与kafka整合

一、状态 1.概述 算子任务可以分为有状态、无状态两种。 无状态:filter,map这种,每次都是独立事件有状态:sum这种,每次处理数据需要额外一个状态值来辅助。这个额外的值就叫“状态”2.状态的分类 (1)托管状态(Managed State)和原始状态(Raw State) 托管状态就是由…...

rabbitmq查看节点信息命令失败

不影响访问rabbitmq&#xff0c;但是无法使用 命令查看节点信息 等 查看节点信息命令&#xff1a;rabbitmq-diagnostics status --node rabbitJHComputer Error: unable to perform an operation on node ‘rabbitJHComputer‘. Please see diagnostics informatio rabbitmq-…...

c语言动态内存分布

前言&#xff1a; 随着我们深入的学习c语言&#xff0c;之前使用的静态内存分配已经难以满足我们的实际需求。比如前面我们的通讯录功能的实现&#xff0c;如果只是静态内存分配&#xff0c;那么也就意味着程序开始的内存分配大小就是固定的&#xff0c;应该开多大的空间呢&am…...

1.3.2有理数减法(第一课时)作业设计

【学习目标】 1&#xff0e;理解有理数减法法则&#xff0c;能熟练地进行有理数的减法运算&#xff0e; 2&#xff0e;感受有理数减法与加法对立统一的辨证思想&#xff0c;体会转化的思想方法&#xff0e;...

vue3 -- ts封装 Turf.js地图常用方法

Turf.js中文网 地理空间分析库,处理各种地图算法 文档地址 安装 Turf 库 npm install @turf/turf创建src/hooks/useTurf.ts 文件1:获取线中心点 效果: 代码: useTurf.ts import * as turf from @turf/turf// 获取线中心点 export class CenterPointOfLine {...

Qt之实现圆形进度条

在Qt自带的控件中&#xff0c;只有垂直进度条、水平进度条两种。 在平时做页面开发时&#xff0c;有些时候会用到圆形进度条&#xff0c;比如说&#xff1a;下载某个文件的下载进度。 展示效果&#xff0c;如下图所示&#xff1a; 实现这个功能主要由以下几个重点&#xff1a…...

C# 图解教程 第5版 —— 第1章 C# 和 .NET 框架

文章目录 1.1 在 .NET 之前1.2 .NET 时代1.2.1 .NET 框架的组成1.2.2 大大改进的编程环境 1.3 编译成 CIL1.4 编译成本机代码并执行1.5 CLR1.6 CLI1.7 各种缩写1.8 C# 的演化1.9 C# 和 Windows 的演化&#xff08;*&#xff09; 1.1 在 .NET 之前 MFC&#xff08;Microsoft Fou…...

electronjs入门-聊天应用程序,与Electron.js通信

随着第一章中构建的应用程序&#xff0c;我们将开始将其与Electron框架中的模块集成&#xff0c;并以此为基础&#xff0c;以更实用的方式了解它们。 过程之间的通信 根据第二章中的解释&#xff0c;我们将发送每个进程之间的消息&#xff1b;具体来说联系人和聊天&#xff1…...

【自用】ubuntu 18.04 LTS安装opencv 3.4.16 + opencv_contrib 3.4.16

1.下载 opencv 3.4.16 opencv_contrib 3.4.16 其中&#xff0c;opencv_contrib解压后的多个文件夹复制到opencv内、合并 声明&#xff1a;尚未验证该方式是否可行 2.安装 参考博文&#xff1a; https://zhuanlan.zhihu.com/p/650792342 https://zhuanlan.zhihu.com/p/8719780…...

递归解析Json,实现生成可视化Tree+快速获取JsonPath | 京东云技术团队

内部平台的一个小功能点的实现过程&#xff0c;分享给大家&#xff1a; 递归解析Json&#xff0c;可以实现生成可视化Tree快速获取JsonPath。 步骤&#xff1a; 1.利用JsonPath读取根&#xff0c;获取JsonObject 2.递归层次遍历JsonObjec&#xff0c;保存结点信息 3.利用z…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

claude3.7高阶玩法,生成系统架构图,国内直接使用

文章目录 零、前言一、操作指南操作指导 二、提示词模板三、实战图书管理系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 在线考试系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 四、感受 零、前言 现在很多AI大模型可以…...

第21节 Node.js 多进程

Node.js本身是以单线程的模式运行的&#xff0c;但它使用的是事件驱动来处理并发&#xff0c;这样有助于我们在多核 cpu 的系统上创建多个子进程&#xff0c;从而提高性能。 每个子进程总是带有三个流对象&#xff1a;child.stdin, child.stdout和child.stderr。他们可能会共享…...

安全领域新突破:可视化让隐患无处遁形

在安全领域&#xff0c;隐患就像暗处的 “幽灵”&#xff0c;随时可能引发严重事故。传统安全排查手段&#xff0c;常常难以将它们一网打尽。你是否好奇&#xff0c;究竟是什么神奇力量&#xff0c;能让这些潜藏的隐患无所遁形&#xff1f;没错&#xff0c;就是可视化技术。它如…...

小白的进阶之路系列之十四----人工智能从初步到精通pytorch综合运用的讲解第七部分

通过示例学习PyTorch 本教程通过独立的示例介绍PyTorch的基本概念。 PyTorch的核心提供了两个主要特性: 一个n维张量,类似于numpy,但可以在gpu上运行 用于构建和训练神经网络的自动微分 我们将使用一个三阶多项式来拟合问题 y = s i n ( x ) y=sin(x) y=sin(x),作为我们的…...

【计算机网络】NAT、代理服务器、内网穿透、内网打洞、局域网中交换机

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;计算机网络 &#x1f339;往期回顾&#x1f339;&#xff1a;【计算机网络】数据链路层——ARP协议 &#x1f516;流水不争&#xff0c;争的是滔滔不息 一、网络地址转…...

Vue3 hooks

export default function(){ let name; function getName(){ return name; } return {name,getName} } use it ----------------------------------------------- import useName from hooks/useName const {name,getName} useName(); 这段代码展示了一个自定义 Vue3钩…...