手撕布隆过滤器:原理解析与面试心得

前言

说来话长,话来说长。前些天我投了一些日常实习的简历,结果足足等了两个礼拜才收到面试通知,看来如今的行情确实是挺紧张的。当时我是满怀信心去的,心想这次一定要好好拷打面试官一番,结果没想到,自我介绍刚一结束,面试官就要开始拷打我了,直接让我手撕布隆过滤器?我当时心里可真是:我勒个豆啊(此处省略无数心里话)。虽然我对它的原理是了解的,但之前还真没有亲手写过。就这样,我开始了这次的手撕布隆过滤器之旅。

一、什么是布隆过滤器

【面试官】:布隆过滤器是什么?你给我讲讲吧。

【自信的我开始吟唱】:

  • 布隆过滤器是一种基于哈希算法的位数组数据结构,主要用于高效地检测一个元素是否在一个集合中。尽管它可以极大地节省存储空间,但由于其允许一定的误报率(即可能会错误地报告一个元素存在于集合中),因此在使用时需要权衡误报的可能性。

  • 当数据量增加时,传统的集合数据结构(如哈希表或列表)会占用大量的内存。而布隆过滤器通过使用多个哈希函数和一个固定长度的位数组来减少内存使用。其主要用途在于能够快速地判断某项元素是否属于特定集合,特别适用于需要快速去重检查的场景,并且它还可以有效地防止缓存穿透攻击。

布隆过滤器原理图

二、实现原理

【面试官点点头,心里暗想着必须要拷打到你】:你跟我讲讲它是如何实现的吧。

【无比自信的我】:

  • 底层原理是通过一个bitmap二进制位数组表示集合来实现的。数组初始位都是0,当添加元素时,会通过多个哈希函数将元素映射到位数组中的多个位置,并将这些位设为1。需要查询某个元素是否存在布隆过滤器时,只需对该元素进行多次哈希,并判断位数组对应位置上的位是否为1即可。
布隆过滤器实现图

三、问题

3.1、 误判率

【面试官追问】:那它二进制位数组,不会有不同元素映射到相同的位置吗?

【我】:

  • 这种情况发生是因为哈希函数的冲突,使得不同元素被映射到相同的位置,导致布隆过滤器的误判率问题。如下图所示:
哈希冲突图
  • 对于误判率,有一个公式可以计算:k:哈希次数,n:元素个数,m:bit数组长度
    p ( n , m , k ) = ( 1 − e − k n / m ) k p(n,m,k) = (1 - e^{-kn/m})^k p(n,m,k)=(1ekn/m)k
    同时还有一个便捷的网站方便我们计算:https://hur.st/bloomfilter/
    使用方法如下:
误判率计算图
  • 通过上述公式我们知道,为了降低误判率,可以采取以下措施:
    1. 增加位数组大小:如果位数组的大小增加,哈希函数分布的碰撞概率降低,从而降低误判率。
    2. 增加哈希函数数量:通过对元素值进行多次哈希操作,得到相对离散的值,但过多的哈希函数会导致效率下降。
    3. 控制插入元素的数量:布隆过滤器的容量是有限的,超过容量后误判率会快速升高。因此,通过限制数据量在布隆过滤器某一阈值比例内,可以保持较低的误判率。尽管如此,布隆过滤器占用的空间相较于其他数据结构还是非常小的。

3.2、 不可删除

【面试官】:除了这个,布隆过滤器还有什么问题吗?

【我】:

  • 布隆过滤器的另一个缺点是无法删除元素。一旦某个元素被添加,无法准确将其从位数组中移除,否则可能会影响其他元素的判定。但是,有一种改进版本的布隆过滤器,称为计数布隆过滤器或动态布隆过滤器(如布谷鸟过滤器),可以在一定程度上解决这一问题。

四、使用场景

【面试官,心想答得还不错,基本都覆盖了】:那你说说布隆过滤器有哪些使用场景吧。

【我】:

  • 常用的话,一般有以下几个场景:
    1. 快速判重:在大规模数据处理场景中,布隆过滤器可以快速判定某个数据是否已经出现,例如用于网页爬虫中避免抓取重复的网页。
    2. 缓存穿透:布隆过滤器可以用于防止缓存穿透。当查询的数据不在缓存中,也不在数据库中时,直接利用布隆过滤器判断该数据是否存在,从而减少对数据库的压力。
    3. 推荐系统中的候选生成:在推荐系统中,布隆过滤器可以用来排除已经推荐过的项目,从而提高推荐的多样性和新颖性。
    4. 恶意域名检测:在网络安全领域,可以使用布隆过滤器来存储已知的恶意域名列表,快速判断新遇到的域名是否可能存在安全风险。
    5. 大数据预筛选:在处理大规模数据集时,布隆过滤器可用于预筛选,减少后续处理的数据量,提高处理效率。

五、如何使用

【面试官】:那你讲讲你在项目中是如何实现的吧。

【我】:

  • 布隆过滤器在 Guava 和 Redisson 中都已经有了实现(这些实现可以直接在网上找到教程,这里就不做具体演示了),我们在使用时可以直接使用这些现有的实现类。

  • 由于我在多个服务下需要实现分布式的共享布隆过滤器数据,所以我选择了使用 Redis 实现布隆过滤器。这样可以确保多个服务之间能够共享布隆过滤器的状态,从而提高系统的整体性能和一致性。如果是单机环境下,直接使用 Guava 的实现即可。

六、Java 手撕

【面试官,心想竟然难不倒你】:那你Java手撕一个吧。

【我】:啊?(然后默默开启了手撕)

在使用Java实现布隆过滤器时,可以借助 BitSet 或自定义的 BitMap 来存储位数组。同时,多个哈希函数可以通过 MessageDigest 或其他常见的哈希库来实现。以下是一个Java布隆过滤器的示例实现概述:

package com.example.provider.utils;import java.util.BitSet;
import java.util.Random;public class BloomFilter {// 一个位数组,用于存储数据private final BitSet bitSet;// 位数组的大小private final int bitSetSize;// 使用的哈希函数数量private final int numHashFunctions;private final Random random;// 布隆过滤器构造函数public BloomFilter(int capacity, int numHashFunctions) {this.bitSetSize = capacity;this.numHashFunctions = numHashFunctions;this.bitSet = new BitSet(bitSetSize);this.random = new Random();}/** 添加元素到布隆过滤器* - 将元素通过多个哈希函数进行散列。* - 将这些哈希值映射到位数组中对应的索引位置,并将这些位置的值设为1。* @param value*/public void add(String value) {for (int i = 0; i < numHashFunctions; i++) {int hash = hash(value, i);bitSet.set(Math.abs(hash % bitSetSize), true);}}/** 检查元素是否存在* - 将元素通过同样的哈希函数散列。* - 检查这些散列值对应的位数组位置是否都为1,* 如果是,则说明元素可能存在(但不保证);如果有任意位置为0,则说明元素一定不存在。* @param value* @return*/public boolean mightContain(String value) {for (int i = 0; i < numHashFunctions; i++) {int hash = hash(value, i);if (!bitSet.get(Math.abs(hash % bitSetSize))) {return false;}}return true;}// 哈希函数,用于生成多个不同的哈希值private int hash(String value, int seed) {random.setSeed(value.hashCode() + seed);return random.nextInt();}// 测试布隆过滤器public static void main(String[] args) {int capacity = 1000; // 位数组大小int numHashFunctions = 5; // 使用的哈希函数数量BloomFilter bloomFilter = new BloomFilter(capacity, numHashFunctions);// 添加元素bloomFilter.add("apple");bloomFilter.add("banana");// 检查元素是否存在System.out.println(bloomFilter.mightContain("apple"));  // 可能存在System.out.println(bloomFilter.mightContain("banana")); // 可能存在System.out.println(bloomFilter.mightContain("grape"));  // 一定不存在}
}
image-20241018224218570

七、总结与思考

【最后,面试官】:时间差不多够了,我们面试就到此为止吧,你先回去等通知吧。

【我】:???

7.1、总结

通过本文,相信大家已经了解了布隆过滤器的基本概念及其在面试中的应用技巧。我们再来谈谈布隆过滤器的设计吧, 它巧妙地利用了位数组和哈希函数的特点,通过将元素映射到位数组中,实现了内存的有效利用。这种设计不仅减少了内存占用,还提高了查询速度,非常适合需要快速去重检查的场景。

7.2、思考

同时,布隆过滤器的设计与应用实现也可以给我们带来以下方面的思考:

  1. 创新思维:布隆过滤器提供了一种全新的视角来看待问题解决方式,它鼓励我们突破传统数据结构的局限,探索更加灵活且高效的解决方案。这种思维方式能够激励我们在面对各类问题时,勇于探索并尝试不同的方法。
    • 事实上,布隆过滤器可以视为是对哈希表的一种创新性应用,它利用哈希表 O(1) 的时间复杂度,并通过位数组来大幅降低内存占用,实现了低空间占用与高响应速度的完美结合。
  2. 资源利用效率:布隆过滤器的设计理念是尽可能地利用有限的存储空间,这启示我们在处理大数据量的问题时,应考虑如何更有效地管理内存或磁盘空间。
    • 例如,由于系统内存极为宝贵,Redis 就采用了多种高空间利用率的数据结构,实现了在小容量内存下的高效存储。
  3. 性能优化:在一些对查询速度要求极高的场景下,布隆过滤器可以显著提高系统的响应速度。这让我们意识到,在设计系统时,应当根据应用场景的具体需求来选择最合适的数据结构和算法。
    • 例如,在 MySQL 中,为了适应磁盘 IO 查询的需求,选择了 B+ 树作为索引结构;而在 Redis 中,则采用了跳表来实现有序集合(Zset),以平衡内存使用与访问效率之间的关系。
  4. 权衡取舍:使用布隆过滤器需要接受一定的误报率,这实际上是在准确性和存储成本之间的一种折衷。这种思想可以推广到其他领域,比如在开发软件时,我们需要在功能全面性与系统复杂度之间找到最佳的平衡点。没有所谓的“最好”方案,只有最适合特定情境的解决方案。
  5. 应用范围扩展:除了布隆过滤器本身的应用外,其背后的思想还可以应用到其他领域。例如,当需要在短时间内处理大量数据时,可以借鉴类似的概念来创建更有效的缓存机制或预筛选机制,从而提升整体系统的性能与效率。

最后,本文到这里就结束了,希望能对你有所帮助。如果觉得内容有用,请给予支持。另外,有兴趣的话可以进一步了解布谷鸟过滤器等改进版本,它们在某些场景下提供了更为灵活的解决方案。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美摄科技云服务解决方案,方案成熟,接入简单

美摄科技作为视频处理领域的先锋&#xff0c;凭借其强大的技术实力和深厚的行业经验&#xff0c;推出了成熟的云服务解决方案&#xff0c;为轻量化视频制作开辟了全新的道路。 一、成熟方案&#xff0c;接入无忧 美摄科技云服务解决方案的最大亮点在于其成熟度和易用性。我们…

java事务讲解(详解篇)

本篇博客将各位介绍事务的相关内容&#xff0c;也算是对事物的大部分知识点进行的一个总结&#xff0c;接下来就跟着我一起来学习学习吧~ 实现事务 实现事务的方式大类共有两大类&#xff0c;一种是编程式事务&#xff0c;另一种是声明式事务。 编程式事务的好处在于他的最小…

Postman 接口测试工具学习使用

目录 Postman 下载 postman界面详解 postman接口测试 操作步骤 postman发送post请求总结 postman断言 状态码断言 响应body正文断言&#xff08;3种场景&#xff09; 响应头断言 响应时间断言 postman集合测试 变量的应用 参数变量 1、环境变量 2、全局变量 3、局…

李德仁院士携实验室及大势文旅团队参加“湖北旅游、武当突破”名家谈,分享数智文旅发展新经验

10月12日上午&#xff0c;2024世界武当太极大会在湖北省十堰市武当山盛大开幕。 2023年国家科学技术最高奖获得者、中国科学院、中国工程院院士、武汉大学李德仁教授携测绘遥感信息工程国家重点实验室&#xff08;后简称“实验室”&#xff09;团队以及大势智慧文旅团队&#…

QUIC 协议的优势

QUIC 协议的优势包括&#xff1a; 快速建立连接&#xff1a;将传输层和加密层的握手合并&#xff0c;减少了连接建立的延迟。QUIC 建连时间大约为 0~1RTT&#xff0c;相比 HTTPS 的 3RTT 建连&#xff0c;具有极大的优势。客户端第一次建连的握手协商需 1RTT&#xff0c;而已建…

其他css的用途

1.animation-fill-mode: backwards; //避免了在动画开始前元素的突然显现&#xff0c;动画必要。 2.用rem响应式字体大小&#xff0c;可以在html样式定义font-size?(例10px&#xff0c;62.5%(100%是16px))。然后样式就可以用rem代替px。 3.color: transparent;: 这行代码将文…

【动手学深度学习】7.3 网络中的网络(NiN)(个人向笔记)

LeNet&#xff0c;AlexNet和VGG都有一个共同的设计模型&#xff1a;通过一系列卷积层和汇聚层来提取空间结构特征&#xff0c;然后通过全连接层对特征的表征进行处理AlexNet和VGG对LeNet的改进主要是在于如何扩大和加深这两个模块网络中的网络(NIN)提出了&#xff1a;在每个像素…

炒股VS炒游戏装备,哪个更好做

这个项目&#xff0c;赚个10%都是要被嫌弃的 虽然天天都在抒发自己对股市的看法&#xff0c;但自己自始至终也没有买进任何一支股票。之所以对这个话题感兴趣&#xff0c;着实是因为手上的游戏搬砖项目也是国际性买卖&#xff0c;跟国际形势&#xff0c;国际汇率挂钩&#xff0…

【D3.js in Action 3 精译_034】4.1 D3 中的坐标轴的创建(中篇):定义横纵坐标轴的比例尺

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

H-TCP 的效率和公平性

昨晚带安孩楼下玩耍&#xff0c;用手机 desmos 作了一组 response curve 置于双对数坐标系&#xff1a; 长肥管道的优化思路都很类似&#xff0c;cwnd 增长快一点&#xff1a; BIC TCP&#xff1a;二分查找逼近 capacity&#xff1b;CUBIC TCP&#xff1a;上凸曲线逼近 capa…

探索光耦:光耦——不间断电源(UPS)系统中的安全高效卫士

在现代社会&#xff0c;不间断电源&#xff08;UPS&#xff09;系统已成为保障关键设备和数据安全的关键设施&#xff0c;广泛应用于企业数据中心、家庭电子设备等场景。UPS能在电力中断或波动时提供稳定电力&#xff0c;确保设备持续运行。而在这套系统中&#xff0c;光耦&…

一款Vue神器!支持拦截、跨域的超级Http请求插件,体积小,兼容全(带私活源码)

今天带来的是一款Vue神器Vue-resource 是那种体积小、兼容全、支持拦截、跨域的超级Http请求插件哦&#xff01; 一、介绍 Vue-resource 是一个用于处理 HTTP 请求和响应的 Vue.js 组件库。它可以轻松地管理 HTTP 请求和响应&#xff0c;并提供了一些简单易用的 API。 Vue-r…

LeetCode刷题日记之贪心算法(四)

目录 前言柠檬水找零根据身高重建队列用最少数量的箭引爆气球总结 前言 在前几篇文章中&#xff0c;我们已经覆盖了贪心算法的基本思路和多种题型。这次我将继续分享几道具有挑战性的贪心题目。希望这篇文章能为大家带来更多解题灵感和技巧✍✍✍ 柠檬水找零 LeetCode题目链接…

javaWeb项目-ssm+vue宠物管理系统功能介绍

本项目源码&#xff08;点击下方链接下载&#xff09;&#xff1a;java-ssmvue宠物管理系统实现源码(项目源码-说明文档)资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;V…

Elasticsearch:Redact(编辑) processor

Redact 处理器使用 Grok 规则引擎来隐藏输入文档中与给定 Grok 模式匹配的文本。该处理器可用于隐藏个人身份信息 (Personal Identifying Information - PII)&#xff0c;方法是将其配置为检测已知模式&#xff0c;例如电子邮件或 IP 地址。与 Grok 模式匹配的文本将被替换为可…

hdfs的分布式存储原理

1.想要把一个大文件存储到hdfs,首先进行划分,将文件划分为一个一个的block,这个block默认为512MB,可修改. 2.备份(也就是副本) 将文件划分后,一个block丢失则原来的大文件没有用了.为了确保文件的安全性,hdfs提供了副本,也就是备份,将文件划分之后hdfs默认将每一个block备份到…

xtrabackup工具介绍、安装及模拟数据库故障使用xtrabackup工具恢复数据等操作详细说明

一、xtrabackup工具介绍 Percona XtraBackup Percona XtraBackup是一个适用于MySQL的开源热备份工具&#xff0c;它在备份期间不锁表。它可以备份InnoDB、XtraDB以及MyISAM存储引擎的表。 2.4版本支持MySQL5.1、5.5、5.6以及5.7。 它有两个实用命令&#xff0c;分别是xtraback…

Python之briefcase生成安卓app解决按钮字母变大写问题

最近修改千纬认字&#xff0c;要在按钮上用拼音&#xff0c;发现拼音会自动变成大写的拼音加音调。 查了一下发现是android的问题。 Android学习之Button按钮在程序运行时全部变大写的处理 - 叶是风的眼泪 - 博客园 按照文中写的 在style.xml文件中加入&#xff1a;<item …

初始爬虫13(js逆向)

为了解决网页端的动态加载&#xff0c;加密设置等&#xff0c;所以需要js逆向操作。 JavaScript逆向可以分为三大部分&#xff1a;寻找入口&#xff0c;调试分析和模拟执行。 1.chrome在爬虫中的作用 1.1preserve log的使用 默认情况下&#xff0c;页面发生跳转之后&#xf…

【SPIE出版,EI检索稳定】2024年人机交互与虚拟现实国际会议(HCIVR 2024,11月15-17日)

2024年人机交互与虚拟现实国际会议&#xff08;HCIVR 2024&#xff09; 2024 International Conference on Human-Computer Interaction and Virtual Reality 官方信息 会议官网&#xff1a;www.hcivr.org 2024 International Conference on Human-Computer Interaction and …