bloom filter

今天的文章和大家一起来学习大数据领域一个经常用到的算法——布隆过滤器。如果看过《数学之美》的同学对它应该并不陌生,它经常用在集合的判断上,在海量数据的场景当中用来快速地判断某个元素在不在一个庞大的集合当中。它的原理不难,但是设计非常巧妙,老实讲在看《数学之美》之前,我也没有听说过这个数据结构,所以这篇文章也是我自己学习的笔记。

 

  原理  

 

在我之前的理解当中,如果想要判断某个元素在不在集合当中,经典的结构应该是平衡树和hash table。但是无论是哪一种方法,都逃不开一点,都需要存储原值。

比如在爬虫场景当中,我们需要记录下之前爬过的网站。我们要将之前的网址全部都存储在容器里,然后在遇到新网站的时候去判断是否已经爬过了。在这个问题当中,我们并不关心之前爬过的网站有哪些,我们只关心现在的网站有没有在之前出现过。也就是说之前出现过什么不重要,现在的有没有出现过才重要。

我们利用平衡树或者是Trie或者是AC自动机等数据结构和算法可以实现高效的查找,但是都离不开存储下所有的字符串。想象一下,一个网址大概上百个字符,大约0.1KB,如果是一亿个网址,就需要10GB了,如果是一百亿一千亿呢?显然这么大的规模就很麻烦了,今天要介绍的布隆过滤器就可以解决这个问题,而且不需要存储下原值,这是一个非常巧妙的做法,让我们一起来看下它的原理。

布隆过滤器本身的结构非常简单,就是一个一维的bool型的数组,也就是说每一位只有0或者1,是一个bit,这个数组的长度是m。对于每个新增的项,我们使用K种不同的hash算法对它计算hash值。所以我们可以得到K个hash值,我们用hash值对m取模,假设是x。刚开始的时候数组内全部都是0,我们把所有x对应的位置标记为1。

举个例子,假设我们一开始m是10,K是3。我们遇到第一个插入的值是”线性代数“,我们对它hash之后得到1,3,5,那么我们将对应的位置标记成1.

 

 

然后我们又遇到了一个值是”高等数学“,hash之后得到1,8,9,我们还是将对应位置赋值成1,会发现1这个位置对应的值已经是1了,我们忽略就好。

 

 

如果这个时候我们想要判断”概率统计”有没有出现过,怎么办?很简单,我们对“概率统计”再计算hash值。假设得到1,4,5,我们去遍历一下对应的位置,发现4这个位置是0,说明之前没有添加过“概率统计”,显然“概率统计”没有出现过。

但是如果“概率统计”hash之后的结果是1,3,8呢?我们判断它出现过就错了,答案很简单,因为虽然1,3,8这个hash组合之前没有出现过,但是对应的位置都在其他元素中出现过了,这样就出现误差了。所以我们可以知道,布隆过滤器对于不存在的判断是准确的,但是对于存在的判断是有可能有错误的

代码

布隆过滤器的原理很简单,明白了之后,我们很容易写出代码:

# 插入元素
def BloomFilter(filter, value, hash_functions):m = len(filter)for func in hash_functions:idx = func(value) % mfilter[idx] = Truereturn filter# 判断元素
def MemberInFilter(filter, value, hash_functions):m = len(filter)for func in hash_functions:idx = func(value) % mif not filter[idx]:return Falsereturn True

  错误率计算  

 

之前的例子当中应该展示得很明白了,布隆过滤器虽然好用,但是会存在bad case,也就是判断错误的情况。那么,这种错误判断发生的概率有多大呢?

这个概率的计算也不难:由于数组长度是,所以插入一个bit它被置为1的概率是,插入一个元素需要插入k个hash值,所以插入一个元素,某一位没有被置为1的概率是。插入n个元素之后,某一位依旧为0的概率是,它变成1的概率是。

如果在某次判断当中,有一个没有出现过的元素被认为已经在集合当中了,那么也就是说它hash得到的位置均已经在之前被置为1了,这个时间发生的概率为:

这里用到了一个极限:

我们来求一下冲突率最低时k的取值,为了方便计算,我们令,代入:

两边求导:

 

我们令导数等于0,来求它的极值:

 

 

我们将代入,可以求出最值时的

同理,我们也可以预设定集合元素n和错判率p,来求解对应的n,同样利用上面的公式推算,可以得到

如果我们允许一定的容错,并且能够大概估计会出现的元素的个数,那么完全可以使用布隆过滤器来代替传统的容器判重的方法。这样不仅效率极高,而且对于存储的要求非常小。

 

  灵魂拷问  

 

原理也明白了,代码也看懂了,这个时候我们来思考一个问题:布隆过滤器可以删除元素吗?

很遗憾,布隆过滤器是不支持删除的。

因为布隆过滤器的每一个bit并不是独占的,很有可能多个元素共享了某一位。如果我们直接删除这一位的话,会影响其他的元素。

还是用上面的例子举例:我们删除线性代数,线性代数对应的位置是1,3,5,虽然我们并没有删除高等数学,但是由于我们移除了高等数学也用到的位置1,如果我们再去判断高等数学是否存在就会得到错误的结果,虽然我们并没有删除它。

当然,在一些必须要有删除功能的场景下,也是有办法的。方法也很简单,就是修改数据结构,将原本每一位一个bit改成一个int,当我们插入元素的时候,不再是将bit设置为true,而是让对应的位置自增,而删除的时候则是对应的位减一。这样,我们删除单个结果就不会影响其他元素了。

这种方法并不是完美的,由于布隆过滤器存在误判的情况,很有可能我们会删除原本就不存在的值,这同样会对其他元素产生影响

布隆过滤器是一个优缺点都非常明显的数据结构,优点非常出色:速度足够快,内存消耗小,代码实现简单。但是缺点也很明显:不支持删除元素,会有误判的情况。这样特点鲜明的数据结构真的非常吸引人。

 

优点:

(1) 、时间复杂度是O(K),k代表hash()的个数

(2) 、空间利用率高;全量存储,但又不存储数据本身

缺点:

(1) 、有误判:两个不同的key通过k个hash()函数之后,可能映射到相同的bit位上

(2) 、不能计数;不能删除元素本身

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

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

相关文章

数据描述

数据描述 1、静态数据 本系统支持用户个人信息存储以及旅游地点、天数、花费金额、景点的推荐存储。因此,本系统需要存储数据库部分信息。 2、动态数据 用户登录信息 用户搜索结果 用户个人信息 旅游分享的攻略 用户个人留言 用户偏好信息 3数据库描述:数…

样式的使用(七)

在自定义组件中使用运行时样式 1、css文件 /* ../assets/CustomComponentStyles.css */ namespace s "library://ns.adobe.com/flex/spark"; namespace mx "library://ns.adobe.com/flex/halo"; .specialStyle{font-size:24;font-weight:bold; } 记得要把文…

skiplist原理与实现

今天继续介绍分布式系统当中常用的数据结构,今天要介绍的数据结构非常了不起,和之前介绍的布隆过滤器一样,是一个功能强大原理简单的数据结构。并且它的缺点和短板更少,应用更加广泛,比如广泛使用的Redis就有用到它。 …

JavaScript与HTML交互——事件

JavaScript和HTML的交互是通过事件实现的。JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。如果JavaScript关注特定类型事件,那么它可以注册当这类事件发生时要调用的句柄。 事件流…

ORMMySQL

概念: ORM:对象关系映射 , 全拼 Object-Relation Mapping ,是一种为了解决面向对象与关系数据库存在的互不匹配现象的技术。主要实现模型对象到关系型数据库数据的映射.比如:把数据库表中每条记录映射为一个模型对象 使用原因: 若不使用ORM框架实现一个应…

实现WM下删除最后一条匹配的通话记录

代码很简单就是操作EDB数据库,先按开始时间降序排序,然后删除第一条匹配的记录。 1 boolDeleteLastCallLogByNumber(LPCTSTR lpszNumber)2 {3 typedef enum4 {5 CT_Reserved0,6 CT_Outgoing1,7 CT_Connected2,8 CT_Ended4,9 CT_Voice_Data8,10 CT_Roam16…

std::string中的反向迭代器rbegin()和rend()

在std::string中,有个接口是rbegin()和rend(),分别表示string字符串的倒数第一个字符和正数第一个字符; rbegin():表示string字符串的倒数第一个字符 rend():表示string字符串的正数第一个字符 分为普通的iterator和…

【转】[教程] CSS入门3:如何插入CSS样式

http://bbs.blueidea.com/forum.php?modviewthread&tid2524742 转载于:https://www.cnblogs.com/lzhitian/archive/2012/11/25/2787164.html

5.spiders(文件夹)

一、基础知识 1. Spiders 文件夹 用于编写爬虫规则,可以在已有的___init__.py文件中编写具体的爬虫规则但是实际开发中可能有多个爬虫规则,所以建议一个爬虫规则用一个文件表示,这样便于维护和管理 2. 代码 # -*- coding: utf-8 -*- import s…

unlink(file_name)

官方描述: unlink的文档是这样描述的: unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open the file is deleted and the space it was using is made available for reuse. …

sql server行级锁,排它锁,共享锁的使用

一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新 A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 脏读 A用户修改了数据,随后B用户又读出该数据,但A用户因为某些原因取消了对数据的修…

日常学习笔记(1)

2019/03/19 21:12 1.函数:numpy.linspace(start,stop,num50,endpointTrue,retstepFalse,dtypeNone)参数: start:scalar类型(个人理解是标量的意思,这不是一个具体的数据类型,而是指某一些数据类型&#xff…

淘宝开发平台知识点一,入门指南

App Key:12038991 App Secret:bb6e1d29db744ed023bfed6a3af6f4f3 1,测试环境下,获取授权码,只有十分钟 http://open.taobao.com/isv/authorize.php?appkey12038991 2,http://container.api.tbsandbox.com/container?…

【转】Linux 下修改Tomcat使用的JVM内存大小

转自 :http://blog.csdn.net/sully2008/article/details/6457570 我的服务器的配置:# OS specific support. $var _must_ be set to either true or false.JAVA_OPTS"-Xms1024m -Xmx4096m -Xss1024K -XX:PermSize512m -XX:MaxPermSize2048m"…

OpenSSL 创建自签名证书

1、生成服务器私钥openssl genrsa -out client.key 40962、生成证书签名请求(CSR)openssl req -new -key client.key -out client.csr3、使用上一步的证书签名请求签发证书openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.…

C++ functor 仿函数

在C中,仿函数不是一个函数,是一个类,这个类实现了函数的功能。 如果我想实现一个求和的功能:定义一个Sum类,让其中的()函数实现这个功能,代码如下: class Sum { public:Sum() default;virtua…

C#中实现鼠标拖动窗体的方法

用C#实现鼠标拖动窗体,方法可能有很多,不过我想最好多还应该是直接记录鼠标的位置,进而完成操作: private void AddList_MouseDown(object sender, MouseEventArgs e){// Gets the x-coordinate and y-coordinate of …

Sql Server 2008将数据库导出sql脚本并导出数据

1.使用Sql Server Management Studio 2008 连接数据库。 2.选中要导出数据的数据库节点,点鼠标右键,在菜单中选择“任务”->“生成脚本”,如图: 3。在弹出的界面中,点2次“下一步”进入如图界面中,把“编…

SQL SERVER 查询表的行数

SELECT OBJECT_NAME(ii.id) TableName ,rows FROM sysindexes ii INNER JOIN sysobjects oo ON ( oo.id ii.idAND oo.xtype U ) WHERE ii.indid < 2 ORDER BY rows desc ; 转载于:https://www.cnblogs.com/JinweiChang/p/10592680.html

C/C++中的占位符

在C、c语言中增加了占位符&#xff0c;目的是为了减少内存的使用&#xff0c;但是现在内存已经不是瓶颈了&#xff0c;进而很少用占位符了 union V {struct X {unsigned char s1:2;unsigned char s2:3;unsigned char s3:3;} x;unsigned char c; } v; v.c 100; printf("%d…