深入浅出聊布隆过滤器(Bloom Filter)

之前在网上看到过这么一段话👇

Data structures are nothing different. They are like the bookshelves of your application where you can organize your data. Different data structures will give you different facility and benefits. To properly use the power and accessibility of the data structures you need to know the trade-offs of using one.

这段话的大意就是:数据结构没有什么不同,在应用程序中他们就像是可以组织数据的书架,不同的数据结构将为您提供不同的便利和好处,你需要仔细权衡自己的需求之后妥善的使用它们。布隆过滤器就是践行这句话的代表,那么今天就和大家深入浅出的聊聊布隆过滤器(Bloom Filter)。

布隆过滤器(Bloom Filter)

还是老规矩,学习一个新知识之前,我们需要了解他的基本概念👇

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

我们在布隆过滤器的基本概念中可以看到这么一句话,布隆过滤器可以用于检索一个元素是否在一个集合中。有些小伙伴可能会问:我们直接用 HashMap 去检索元素不就行了吗,为什么还要用布隆过滤器呢?HashMap 确实可以帮助我们实现这个功能,而且 HashMap 通过一次运算就能确定某个元素的位置,也就可以帮助我们检查某个元素是否在一个集合中。那么我们接下来再思考一个问题:如果这个元素集合中有十亿个随机数,那我们怎样来判断某个数是否存在呢?

如果元素集合中包含了十亿个随机数的话,那么首先就会给我们带来空间上的问题,按一个随机数占4个子节计算的话,这十亿个随机数就要占用将近4G的存储空间,空间消耗就非常大,这时候就需要用到布隆过滤器(Bloom Filter)来帮助我们解决这个问题了。

🍓🍓布隆过滤器的基本思想🍓🍓

上面我们提到了元素集合中包含了十亿个随机数,如果直接存储这十亿个元素的话就需要占用很大的空间,所以我们肯定不能直接存储元素。那么我们该怎样存储呢?存储方式也是十分巧妙的,可以采用位数组的方式,不直接存储元素,而是存储元素是否存在的状态,这样就可以节约大量的存储空间~(也不知道大神们是怎么想到这么巧妙的办法的😂)

下面我们就一起看看布隆过滤器是怎么判断一个元素是否在一个集合中的👇

🥝 ① 🥝 现在有一个集合和一个初始状态都为0的位数组

🥝 ② 🥝 集合中的元素经过N个散列函数计算出元素在数组当中的位置,并且将数组中对应位置的0改成1

🥝 ③ 🥝 如果此时需要判断元素X是否存在,那么元素X也会经过这N个散列函数的运算而得到数组中的若干个位置,如果得到的若干个位置中的值均为1,那么则证明元素X很可能存在与集合当中,反之则证明元素X一定不存在于集合当中。如下图所示,此时元素X经过N个散列元素计算出的位置上所存储的值不都是1,那么就证明元素X不存在集合中。

🍓🍓布隆过滤器的特性🍓🍓

在上面我们讲到了布隆过滤器的思想,在第③点中有这样一句话:如果得到的若干个位置中的值均为1,那么则证明元素X 很可能 存在与集合当中。为什么说全都是1的情况是很可能存在,而不是一定存在呢?这就和哈希函数的特点有关系了...

我们都知道哈希函数是可以将任意大小的输入数据转换成特定大小的输出数据的函数(转换后的数据称为哈希值),哈希函数还有以下两个特点:

  • 如果根据同一个哈希函数得到的哈希值不同,那么这两个哈希值的原始输入值肯定不同。
  • 如果根据同一个哈希函数得到的两个哈希值相等,两个哈希值的原始输入值有可能相等,有可能不相等。

这就类似于 Java 中两个对象的 HashCode 相等,但是对象本身不一定相等的道理。说白了,通过散列函数计算后得到位数组上映射点的值全都是1,不一定是要查询的这个变量之前存进来时设置的,也有可能是其他元素映射的点。这也就引出了布隆过滤器的一个特性:存在一定的误判

在英雄联盟里,你可以完全信任布隆,但是写代码时还是得提防着点😂

那么我们能不能删除位数组中的元素呢?很显然是不行的,因为在位数组上的同一个点有可能有多个输入值映射,如果删除了会影响布隆过滤器里其他元素的判断结果。这也就是布隆过滤器的另一个特性:不能删除布隆过滤器里的元素

所以我们就可以总结出布隆过滤器的优缺点👇

🍎优点🍎:在空间和时间方面,都有着巨大的优势。因为不是存完整的数据,是一个二进制向量,能节省大量的内存空间,时间复杂度方面,由于计算时是根据散列函数计算查询的,那么假设有N个散列函数,那么时间复杂度就是O(N);同时在存储元素时存储的不是元素本身,而是二进制向量,所以在一些对保密性要求严格的场景有一定优势。

🍌缺点🍌:存在一定的误判(存进布隆过滤器里的元素越多,误判率越高);不能删除布隆过滤器里的元素,随着使用的时间越来越长,因为不能删除,存进里面的元素越来越多,导致占用内存越来越多,误判率越来越高,最后不得不重置。

🍓🍓布隆过滤器的应用🍓🍓

我们都听说过“缓存穿透”,那我们应该如何解决缓存穿透呢?没错,就是通过布隆过滤器来解决这个问题💪。

缓存穿透的问题主要是因为传进来的 Key 值在 Redis 中是不存在的,那么就会直接打在数据库上,从而增大数据库的压力。针对这种情况,可以在 Redis 前加上布隆过滤器,预先把数据库中的数据加入到布隆过滤器中,在查询 Redis 之前先通过布隆过滤器判断 Key 值是否存在,如果不存在就直接返回,如果 Key 值存在的话,则按照原来的流程继续执行。

解决缓存穿透利用的就是布隆过滤器判断结果为不存在的话就一定不存在这一个特点,但是由于布隆过滤器有一定的误判,所以并不能说完全解决缓存穿透,但是能很大程度缓解缓存穿透的问题。

🍓🍓模拟实现布隆过滤器🍓🍓

最后贴上一段代码,来模拟实现一下布隆过滤器👇

import java.util.BitSet;/*** @description: MyBloomFilter* @author: 庄霸.liziye* @create: 2022-04-01 16:50**/
public class MyBloomFilter {/*** 一个长度为10亿的比特位*/private static final int DEFAULT_SIZE = 256 << 22;/*** 为了降低错误率,使用加法hash算法,所以定义一个8个元素的质数数组*/private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};/*** 相当于构建8个不同的hash算法*/private static HashFunction[] functions = new HashFunction[seeds.length];/*** 初始化布隆过滤器的bitmap,即位数组*/private static BitSet bitset = new BitSet(DEFAULT_SIZE);/*** 添加数据** @param value 需要加入的值*/public static void add(String value) {if (value != null) {for (HashFunction f : functions) {//计算 hash 值并修改 bitmap 中相应位置为 truebitset.set(f.hash(value), true);}}}/*** 判断相应元素是否存在* @param value 需要判断的元素* @return 结果*/public static boolean contains(String value) {if (value == null) {return false;}boolean ret = true;for (HashFunction f : functions) {ret = bitset.get(f.hash(value));//一个 hash 函数返回 false 则跳出循环if (!ret) {break;}}return ret;}/*** 测试*/public static void main(String[] args) {for (int i = 0; i < seeds.length; i++) {functions[i] = new HashFunction(DEFAULT_SIZE, seeds[i]);}//添加1亿个元素for (int i = 0; i < 100000000; i++) {add(String.valueOf(i));}String id = "123456789";add(id);System.out.println("元素 123456789 是否存在:" + contains(id));System.out.println("元素 234567890 是否存在:" + contains("234567890"));}
}class HashFunction {private int size;private int seed;public HashFunction(int size, int seed) {this.size = size;this.seed = seed;}public int hash(String value) {int result = 0;int len = value.length();for (int i = 0; i < len; i++) {result = seed * result + value.charAt(i);}int r = (size - 1) & result;return (size - 1) & result;}
}复制代码


作者:不肯过江东丶
链接:https://juejin.cn/post/7083294020323000356
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


---------------------
作者:栗少
来源:CSDN
原文:https://blog.csdn.net/weixin_38556197/article/details/124111236
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件

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

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

相关文章

WinForm(五)控件和它的成员

窗体无疑是WinForm的主角&#xff0c;每个窗体都是用一个class来承载&#xff0c;那么窗体的控件&#xff0c;就是类中的私有字段了。每个窗体有三个文件&#xff0c;两个.cs文件&#xff0c;是一个分部类&#xff0c;Designer.cs是自动生成的C#代码&#xff0c;一般是拖拽控件…

一文详解|增长那些事儿

目录 增长的背景 1.1 增长的定义 1.2 如何判断事物是否在增长 1.3 如何判断事物能否持续增长 如何进行增长 2.1 寻找增长机会点&#xff08;人的能力&#xff09; 2.1.1 发散与收剑找机会点 2.1.2 实验分析验证 2.1.3 增长洞察提取策略 2.1.4 如何找到大机会 2.2 设…

在MVC项目中使用Ninject

项目结构图&#xff1a; App_start文件夹中的文件是VS自己创建的&#xff0c;其中NinjectWebCommon类在创建之初并不存在。后面会再次提到&#xff01; 添加一个Home控制器。代码如下&#xff1a; using EssentialTools.Models; using Ninject; using System; using System.Col…

一文学会Autofac的基础操作:几种实现注册方式、3种注入方式、生命周期、AOP以及过滤器实现依赖注入...

前言&#xff1a;直接开干。使用Autofac进行服务注册实践&#xff1a;新建三个项目&#xff0c;分别是webapi项目 Wesky.Core.Autofac以及两个类库项目 Wesky.Core.Interface和Wesky.Core.Service。在Webapi项目下&#xff0c;引用Autofac的三个包&#xff1a;Autofac、Autofac…

JavaScript数组迭代方法(图解)

转载于:https://www.cnblogs.com/seanna/p/6724032.html

Rider调试ASP.NET Core时报thread not gc-safe的解决方法

新建了一个ASP.NET Core 5.0的Web API项目&#xff0c;当使用断点调试Host.CreateDefaultBuilder(args)时&#xff0c;进入该函数后查看中间变量的值&#xff0c;报错Evaluation is not allowed: The thread is not at a GC-safe point。在群里问了也没人回应&#xff0c;可能没…

The SDK platform-tools version ((23)) is too old to check APIs compiled with API 26;

好像是更新过啥SDK之后&#xff0c;项目一直在包名的那一行显示红线&#xff0c;不过是不报编译错误的&#xff0c;就是看着老扎心老扎心的&#xff0c;开始以为是指定的SDK版本的问题&#xff0c;修改后发现无效&#xff0c;最后找到方法解决&#xff1a; 打开SDK Manager ---…

oracle 各种日期函数格式和操作

2019独角兽企业重金招聘Python工程师标准>>> ORACLE日期时间函数大全 TO_DATE格式(以时间:2007-11-02 13:45:25为例) Year: yy two digits 两位年 显示值:07 yyy three digits 三位年 显示值:00…

火山引擎李玉光:字节跳动大规模K8s集群管理实践

2022年5月31日&#xff0c;在CSDN云原生系列在线峰会第6期“K8s大规模应用和深度实践峰会”&#xff0c;火山引擎资深云原生架构师李玉光分享了《字节跳动大规模K8s集群管理实践》。 字节跳动云原生体系 字节跳动内部云原生技术的使用贯穿组织技术体系各层面&#xff0c;整体如…

(7)关于margin的一些想法2.0

这篇主要讨论的就是margin负值与float的关系。 首先&#xff0c;例子。 <!doctype html> <html> <head> <meta charset"utf-8"> <title>无标题文档</title> <style typetext/css> html,body{padding:0;margin:0;} div{wid…

什么是SRE?一文详解SRE运维体系

在任何有一定规模的企业内部&#xff0c;一旦推行起来整个SRE的运维模式&#xff0c;那么对于可观测性系统的建设将变得尤为重要&#xff0c;而在整个可观测性系统中。 可观测性系统 在任何有一定规模的企业内部&#xff0c;一旦推行起来整个SRE的运维模式&#xff0c;那么对于…

python初探

python近两年似乎已经很热了&#xff0c;不了解一下怎么能行呢&#xff0c;似乎python最大的优点就是简洁、易懂、优雅。目前豆瓣、知乎等后台服务使用的也都是python语言。 python一般可以用于网站服务、小工具、数据分析等工作。它作为高级语言&#xff0c;和js一样&#xff…

solr5.5索引mysql数据(新手总结)

一 solr5.5环境部署到Eclipse(luna版&#xff09; solr部署参见&#xff1a;http://blog.csdn.net/csmnjk/article/details/64121765 二 Ik分词器设置 IK分词器设置参见:http://blog.csdn.net/csmnjk/article/details/51693578 solr4版本的schema.xml文件对应solr5版本的manage…

老板加薪!看我做的WPF Loading!!!

老板加薪&#xff01;看我做的WPF Loading&#xff01;&#xff01;&#xff01;控件名&#xff1a;RingLoading作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visua…

如何避免下重复订单

电子交易的一个很基本的问题&#xff0c;就是避免用户下重复订单。用户明明想买一次&#xff0c;结果一看下了两个单。如果没有及时发现&#xff0c;就会带来额外的物流成本和扯皮。对商家的信誉也不好看。 从技术上看&#xff0c;这是一个分布式一致性问题&#xff1b;但实际…

图像分类学习笔记

1.计算机认识图像的方式&#xff1a;都是数字。例如一个 128X128 的3通道的图片 是由 128X128X3个数字 组成的。 2.面临的难点&#xff1a;一幅图可以说明。 3.分类器 A&#xff1a;Nearest Neighbor Classifier&#xff1a;与CNN无关&#xff0c;但是可以帮助我们理解一下分类…

知物由学 | 干货!一文了解安卓APP逆向分析与保护机制

“知物由学”是网易云易盾打造的一个品牌栏目&#xff0c;词语出自汉王充《论衡实知》。人&#xff0c;能力有高下之分&#xff0c;学习才知道事物的道理&#xff0c;而后才有智慧&#xff0c;不去求问就不会知道。“知物由学”希望通过一篇篇技术干货、趋势解读、人物思考和沉…

[转]以终为始,详细分析高考志愿该怎么填

为什么写这篇文章&#xff1f; 之所以写本文&#xff0c;是因为我自己有用处。 我简要介绍&#xff0c;长话短说。我从一个普通的211本科毕业&#xff0c;已经接受社会"毒打"多年&#xff0c;回想起高考填志愿&#xff0c;依然会觉得有些许遗憾。我在贵州省的一个小县…

ASP.NET Core 中的重定向

前言在《如何使用ASP.NET Core Web API实现短链接服务》中&#xff0c;我们使用了Redirect方法返回跳转状态码:[HttpGet("{shortUrl}")] public IActionResult GetUrl(string shortUrl) {var hashids new Hashids("公众号My IO", minHashLength: 6);var i…

客户端应用试用限制设计

1.概要最近接到公司安排的任务给客户端设计一个“试用30天”的一个需求&#xff0c;其功能主要是为了防止客户拿到产品之后不支付尾款继续使用。众所周知靠纯软件想防“盗版”&#xff0c;“限制试用”等做法是行业难题。只要价值足够高一定有人会破解绕过你的所有防线达到免费…