详细介绍:Java数据结构第二十七期:布隆过滤器,用 “模糊” 换高效的查重黑科技

news/2025/9/30 13:08:39/文章来源:https://www.cnblogs.com/yxysuanfa/p/19120922

专栏:Java数据结构秘籍

个人主页:手握风云

目录

一、布隆过滤器的提出

二、布隆过滤器的概念

三、布隆过滤器的插入

四、布隆过滤器的查找

五、布隆过滤器的模拟实现

六、布隆过滤器的删除

七、布隆过滤器的优点

八、布隆过滤器的缺陷

九、布隆过滤器的应用场景


一、布隆过滤器的提出

        日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素时,将它和集合中的元素直接比较即可。

        一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来了。

        比如说,一个像 Yahoo、Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。

        如果用哈希表,每存储一亿个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个 email 地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的。

  • 用哈希表存储用户记录,缺点:浪费空间;
  • 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了;
  • 将哈希与位图结合,即布隆过滤器;

二、布隆过滤器的概念

        布隆过滤器是1970 年由布隆提出的概率型数据结构,用于高效判断一个元素是否存在于集合中。它通过多个哈希函数将元素映射到一个位图(BitMap)的不同位置,利用比特位的 “集体状态” 判断存在性,具有高空间效率和常数时间复杂度的查询 / 插入能力,但允许一定概率的误判(假阳性)。

三、布隆过滤器的插入

        比如下图中,插入"baidu"字符串通过3个哈希函数,3 个哈希函数映射到位图的位置 1、5、8,将对应索引的0置为1;插入"google"字符串映射到位置5、7、10。

四、布隆过滤器的查找

        布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零, 代表该元素一定不在哈希表中,否则可能在哈希表中。

        注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。

五、布隆过滤器的模拟实现

import java.util.BitSet;
class SimpleHash {public int cap; // 当前容量public int seed; // 随机数public SimpleHash(int cap, int seed) {this.cap = cap;this.seed = seed;}
}

        关于随机数的生成,我们可以看下HashMap.put()的源码。所以我们也可以自己实现

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

        但是我们需要根据随机数的不同来生成随机函数。我们可以利用(cap-1)*seed & hash。

int hash(String key) {int h;// (n - 1) & hash找到数组下标// 将key的hashCode与自身右移16位后的结果进行异或运算,增加哈希的随机性return (key == null) ? 0 : (seed * (cap - 1)) & ((h = key.hashCode()) ^ (h >>> 16));
}

        接下来使用BitSet作为底层存储结构,它是一个位数组,默认大小为1 << 20。并且这里使用了多个通过HashSimpleHash对元素进行多次哈希计算定义了6个不同的种子值,每种子值对应一个哈希函数实例,用于产生不同的哈希值,这种多哈希函数的设计可以降低哈希冲突的概率。

public class MyBloomFilter {// 布隆过滤器的大小public static final int DEFAULT_SIZE = 1 << 20;public BitSet bitSet; //位图public int usedSize; // 已使用的位数public static final int[] seeds = {5, 7, 11, 13, 27, 33};public SimpleHash[] simpleHashes;// 初始化伪数组大小和哈希函数数组public MyBloomFilter() {bitSet = new BitSet(DEFAULT_SIZE);simpleHashes = new SimpleHash[seeds.length];for (int i = 0; i < seeds.length; i++) {simpleHashes[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);}}
}

        接下来需要实现布隆过滤器的添加和查找方法。

/*** 向布隆过滤器中添加元素* @param val 需要添加的元素*/
public void add(String val) {
}
/*** 判断布隆过滤器中是否包含指定元素,存在一定误判性* @param val 需要判断的元素* @return 如果包含返回true,否则返回false*/
public boolean contains(String val) {
}

        当添加元素时:使用多个不同的哈希函数对元素进行哈希计算;将每个哈希值对位数组长度取模,得到多个位置;将这些位置在位数组中对应的比特位设置为1。

/*** 向布隆过滤器中添加元素* @param val 需要添加的元素*/
public void add(String val) {// 让多个哈希函数分别处理当前数据for (SimpleHash simpleHash : simpleHashes) {int index = simpleHash.hash(val);// 将对应位置的bit设置为1bitSet.set(index);}
}

        查询时,用同样的哈希函数计算位置,检查所有对应位是否都为1。对于每个哈希函数,计算输入值val的哈希值,得到在位数组中的位置。检查位数组中这些位置是否都为1:如果有任何一位为0,则该元素一定不存在于集合中,返回false;如果所有位都为1,则该元素可能存在于集合中,返回true。

/*** 判断布隆过滤器中是否包含指定元素,存在一定误判性* @param val 需要判断的元素* @return 如果包含返回true,否则返回false*/
public boolean contains(String val) {if (val == null) {return false;}// 让多个哈希函数分别处理当前数据for (SimpleHash simpleHash : simpleHashes) {int index = simpleHash.hash(val);// 如果有一个位置的bit为0,则说明该元素一定不存在if (!bitSet.get(index)) {return false;}}return true;
}

        测试用例:

public static void main(String[] args) {MyBloomFilter myBloomFilter = new MyBloomFilter();myBloomFilter.add("Baidu");myBloomFilter.add("Google");myBloomFilter.add("bytedance");myBloomFilter.add("Facebook");myBloomFilter.add("YouTube");myBloomFilter.add("Tencent");System.out.println(myBloomFilter.contains("Baidu"));System.out.println(myBloomFilter.contains("MicroSoft"));
}

六、布隆过滤器的删除

        布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。比如我们把"Baidu"的位置都置为0,就会影响到"Google"的映射。

七、布隆过滤器的优点

  1. 增加和查询元素的时间复杂度为:0(K),(K为哈希的数的个数,一般比较小),与数据量大小无关;
  2. 哈希函数相互之间没有关系,方便硬件并行运算;
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势;
  4. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算。

八、布隆过滤器的缺陷

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中;
  2. 不能获取元素本身;
  3. 一般情况下不能从布隆过滤器中删除元素。

九、布隆过滤器的应用场景

  1. 网贡爬虫对URL的去重,避免爬去相同的URL地址;
  2. 垃圾邮件过滤,从数十亿个垃圾邮件列表中判断某邮箱是否是垃圾邮箱;
  3. 解决数据库缓存击穿,黑客攻击服务器时,会构建大量不存在于缓存中的key向服务器发起请求,在数据量足够大的时候,频繁的数据库查询会导致挂机。

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

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

相关文章

Nginx 反向代理与负载均衡核心内容总结 - 实践

Nginx 反向代理与负载均衡核心内容总结 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &q…

没有网站的域名佛山网站搜索排名

Servlet是运行在Web服务器或应用服务器上的java程序&#xff0c;它是一个中间层&#xff0c;负责连接来自web浏览器或其他HTTP客户程序和[HTTP服务器]上应用程序 Servlet执行下面的任务: 1&#xff09;读取客户发送的显示数据。 2&#xff09;读取由浏览器发送的隐式请求数据。…

自己注册了个域名想做一个网站网站建设属于服务还是货物

模块简介&#xff1a; requests 库是一个 python中比较有名的 http请求的库&#xff0c;能处理 get,post,put,delete 等 restful请求&#xff0c;能设置 header&#xff0c;cookie,session 等操作&#xff0c;也是作为爬虫的基础库&#xff0c;它目前还不能异步请求,如果要支持…

海口 做网站百度搜一下

一、GoLand显示环境如下 修改环境变量 新建系统变量 GOROOT&#xff1a; D:\ENSPACE\golandsdk\1.23.1\go1.23.1新建系统变量 GOPATH&#xff1a;工作目录&#xff08;在下面目录下新建目录&#xff1a;src,项目工程目录都要建在src下如&#xff1a;demo1 demo2&#xff09; D…

这款免费Windows优化神器!只有5M电脑绿色工具!ZyperWin++下载安装教程

软件介绍 今天给大家安利一款我最近发现的宝藏软件,ZyperWinOptimize(ZyperWin++)是一款开源的 Windows 优化工具,基于 .NET + SunnyUI 的开源、轻量级 Windows 系统优化工具,适用于 Windows 7 至 Windows 11 系统…

完整教程:Clustering|聚类

完整教程:Clustering|聚类pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco",…

网站制作可以询价么找建筑类工作哪个网站好

感受好久没写中文技术文章了。说实话&#xff0c;学东西都是基于英文&#xff0c;或者 别人从英文翻译成中文 咱们再捡二手货学习。因此用中文写技术文章怎么都感受是在骗人&#xff0c;怎么都以为很别扭。编程可是这一次的主角是百度。框架虽然认真来说&#xff0c;全部编程语…

深入解析:DAY 04 CSS文本,字体属性以及选择器

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

原核蛋白表达与真核蛋白表达的差异选择

原核蛋白表达与真核蛋白表达的差异选择 重组蛋白表达是现代分子生物学、结构生物学和生物制药研究中的核心技术。不同蛋白(尤其是真核来源的蛋白)在异源表达时可能面临折叠、修饰、毒性、可溶性、活性保持等挑战。常…

网站开发找哪家好产品做网站推广

题目链接&#xff1a;https://codeforces.com/contest/1105 C. Ayoub and Lost Array 题目大意&#xff1a;一个长度为n的数组&#xff0c;数组的元素都在[L,R]之间&#xff0c;并且数组全部元素的和可以被3整除&#xff0c;问有多少种方法构建出该数组。答案模1000000007 例 输…

企业网站应该找谁做seo排名教程技术

1、位存储 只有0和1两种状态&#xff01; Bitmap 位图&#xff1a;数据结构&#xff0c;都是操作二进制位来进行记录 登录/未登录 活跃/不活跃 打卡 两个状态的都可以使用Bitmap&#xff01; 2、常用命令 2.1、用Bitmap来记录 周一到周日的登陆情况 127.0.0.1:6379> …

【MacOS】彻底卸载Navicat

sudo rm -Rf /Applications/Navicat\ Premium.appsudo rm -Rf /private/var/db/BootCaches/CB6F12B3-2C14-461E-B5A7-A8621B7FF130/app.com.prect.NavicatPremium.playlistsudo rm -Rf ~/Library/Caches/com.apple.hel…

SpringAI 实战:解除 Netty 超时难题,优化 OpenAiApi 配置

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

泛型类型参数

泛型类型参数在Java泛型中,"T" 是一个类型参数的占位符,代表"Type"。它是一个约定俗成的命名方式:T:Type(类型)E:Element(元素)K:Key(键)V:Value(值)N:Number(数字)

哪些网站可以做一些任务挣钱网站前台做哪些工作

动态路由协议/静态路由协议 静态路由协议和动态路由协议的区别&#xff1a; 静态路由协议的缺点&#xff1a; 配置繁琐 针对拓扑的变化不能够自动收敛 只适用于小型网络 静态路由协议优点&#xff1a; 占用资源少 安全 稳定 动态路由协议的优点&#xff1a; 配置简单 针对拓…

CF1584E Game with Stones 题解

Sol 考虑一个区间 \([l,r]\) 要如何才能合法。 显然 \(l\) 只能和 \(l+1\) 消耗,所以 \(a_{l+1}\ge a_l\)。 然后接着让 \(l+1\) 和 \(l+2\) 消耗,所以 \(a_{l+2}\ge a_{l+1}-a_l\)。 以此类推 \(a_{i}\ge a_{i-1}-a…

做网站用什么插件使用html制作个人主页

目录 一、基础知识 二、两类密钥体制 三、数字签名实现功能 四、鉴别 五、密钥分配 六、互联网使用的安全协议 6.1网络层安全协议 6.2传输层安全协议 七、系统安全 7.1防火墙 7.2入侵检测系统 一、基础知识 计算机网络的通信方面面临两大类威胁&#xff1a;被动攻击…

高德解包和打包报错

解包和打包报错 解包报错 PS D:\code\amapauto-editor\resources> java -jar apktool.jar d gaode.apk -f I: Using Apktool 2.12.1 on gaode.apk with 8 threads I: Baksmaling classes.dex... I: Loading resourc…

用友U8Api 接口对接

U8 API接口集成主要用于第三方系统与用友U8ERP系统进行数据交互,实现业务系统对接 文档中接口集成了用友U8各个版本的数据对接功能,支持U8.9到 U818.0版本要求,摒弃了eai、openapi、api、暴力插库等接口的方式,全部…

实用指南:如何在WordPress中添加短代码

实用指南:如何在WordPress中添加短代码pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…