哈希与位图的结合--布隆过滤器与哈希切分

这篇具有很好参考价值的文章主要介绍了哈希与位图的结合--布隆过滤器与哈希切分。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一章讲了位图,我们知道了在海量数据中查找一个数是否存在,可以用每一个比特位标识。

但是位图只能处理整数,要是字符串或者其它的呢,位图便无法处理了,这个时候便需要用到布隆过滤器了.

目录

布隆过滤器提出

布隆过滤器概念

布隆过滤器的实现以及最优值

 哈希切分


布隆过滤器提出

我们在看b站视频时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。问题来了,b站推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当b站推荐系统推荐视频时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。 如何快速查找呢?
1. 用哈希表存储用户记录,缺点:浪费空间
2. 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了。
3. 将哈希与位图结合,即布隆过滤器

布隆过滤器概念

布隆过滤器(Bloom Filter)是一种概率型的数据结构,用于快速判断一个元素是否存在于一个集合中。它基于位图(或称为位数组)和多个哈希函数构成。

布隆过滤器的主要目标是在存储空间相对较小的情况下,实现高效的成员查询。它通过使用多个哈希函数将要查询的元素映射到位图中的多个位上。当一个元素要插入布隆过滤器时,通过多个哈希函数计算出多个索引位置,并将对应位设置为1。当判断一个元素是否存在时,再次通过多个哈希函数计算出多个索引位置,并检查对应位是否都为1。如果有任何一个位为0,则可以确定该元素一定不存在于集合中;如果所有位都为1,则表示该元素可能存在于集合中,但有一定的误判率

注意,只有判断一个数据存在的时候才会有误判。

因为如果判断一个数据它存在了,但是它可能和别的数据冲突了,即别的数据占的这些位恰好是这个数据的那些位。这样就会造成误判。

我举个例子可以说明一下:

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

而判断一个数据不存在这是绝对不可能误判的,因为不存在说明别的数据都还没有占用这些位,一定没有和这个数据相同的数据存在,因为如果存在了,对应的所有位就都是1了,此时便会判它存在了.

这个误判是不可能去掉的,但是可以降低误判的概率。比如增加多个哈希函数。

这样的话,每个数据对应的位就会多了,这样重合的概率就会更低。

例如之前一个数据对应两个位,现在对应了三个位,是不是重合的概率又降低了呢?

虽然原来我们两个位冲突了,现在又多了一个位,又多了一个机会,此时便相当于降低了误判率。

但是也不能盲目的增加哈希函数,具体会有一个合适的值.

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

 如果映射函数的越多,空间消耗就会增多,就失去了原本的优势

这个会被应用在哪些地方呢?

比如访问一个网站,会有黑名单用户,每个用户访问的时候,都需要判断一下是不是黑名单用户。

我们如果每次都要去数据库中查找,那么经过网络传输等过程会使效率变得非常低下,所以是不被采用的。

这个时候便用到了我们的布隆过滤器,每当有用户访问,先查找存在不存在,有两种情况:

1.存在:如果存在,我们才再次需要去数据库中查找,因为存在会有误判,万一人家不是黑名单用户,你却误判成了黑名单,这当然是不合理的,这个时候才去数据库中查找。

2.不存在:不存在那就说明这个人一定不是黑名单用户了,因为不存在不会有误判,直接返回即可:

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

还有一个我们常见的情景,就是在注册申请一个账号的时候,比如输入昵称的时候,有的后面会立马显示“此昵称已被占用”。这其实就是应用了布隆过滤器。

当你输入一个名字的时候,如果利用布隆过滤器查找,发现存在了,会给你提示已经存在,但是这个名字一定是存在的吗?那不一定,毕竟有可能是误判。

但是你也不会察觉到,占用就占用了呗,然后换一个就行。当然这也对这个公司有好处,报总比不报好,万一就是已经存在的呢,这样就不好了。

但是不存在的话,就不会报,因为它一定不存在了。这也是前面一直所说的.

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

布隆过滤器的实现以及最优值

由于C++STL库中并没有布隆过滤器,所以得靠我们自己手动实现。

首先由于布隆过滤器的数据类型不再只是整数,所以我们要利用模板。

可以定义K为数据的类型,那么我们每次需要给位图开多大空间呢?

总不能一上来开41亿,比如就100个数据,开这么大就有点浪费了,所以再给出一个非类型模板参数N,代表数据的个数,然后在成员变量中定义一个_ratio表示倍数,每次开N*_ratio的空间即可。

可能有同学会有疑问,之前位图不是说开多少空间取决于数据范围吗?这个怎么不用?

因为位图采用的是直接定址法,它这个数据是多少,它就会对应在位图的相应位置,所以数据范围的大小决定了开多少空间。

而布隆过滤器是对每个数据采用了哈希映射,而且是多个哈希映射,这样当然不需要多么大的空间了。比如一个数据1,和99999999,采用了哈希映射后,1对应的位图中是1,2,3,而99999999对应的位图是1,3,4、这个只是一个假设,目的是理解为什么不用根据数据范围来开空间。

然后毋庸置疑,就是对应的哈希函数模板,那么具体定义多少个哈希映射函数呢

不仅如此,布隆过滤器(内部其实就是一个位图)的长度也影响了误判率,那么长度为多少合适呢?

这个有一套数学理论和实验证明,这里我们只看一下最终结果和公式:

“很显然,过小的布隆过滤器很快所有的 bit 位均为 1,那么查询任何值都会返回“可能存在”,起不到过滤的目的了。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。

另外,哈希函数的个数也需要权衡,个数越多则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低;但是如果太少的话,那我们的误报率会变高”

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误判率

那么具体该如何选择k和m的值是最优的呢?

有两个公式:

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

根据这两个公式可以选出最优的m和k的值。

然后下面就是布隆过滤器的代码,代码不唯一的,具体根据m和k的值进行调整。

//N表示准备要映射N个值.
template<size_t N,class K,
class Hash1,class Hash2,class Hash3>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		_bits.set(hash1);
		size_t hash2 = Hash2()(key) % (_ratio * N);
		_bits.set(hash2);
		size_t hash3 = Hash3()(key) % (_ratio * N);
		_bits.set(hash3);
	}
	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		if (!bits.test(hash1))
			return false;
		size_t hash2 = Hash2()(key) % (_ratio * N);
		if (!bits.test(hash2))
			return false;
		size_t hash3 = Hash3()(key) % (_ratio * N);
		if (!bits.test(hash3))
			return false;
		return true;//可能存在误判
	}
private:
	const static size_t _ratio = 5;
	bitset<_ratio*N> _bits;
};

这是主体部分的代码,可以看到以上代码中用了3个哈希函数,具体每个哈希算法怎么实现,则由自己进行决定。也可以在网上搜索一些哈希相关的算法。

然后我们定义3个类,每个类中重载()运算符,然后进行哈希算法的实现。最后创建对象时,把这三个类传入即可。

下面讲解两道布隆过滤器相关的题目:

1、 如何扩展BloomFilter使得它支持删除元素的操作?

首先我们要知道,布隆过滤器一般情况下是不能被删除的。大家想一想,为什么?

因为位图中的某一个位可能是两个字符串的位,即它们有公共比特位,例如这张图:

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

如果我们想删除百度,即将百度的对应的位全部置为0,b站也会受到影响, 最后只剩下1个位了。

这样在查找的时候,便也查找不到b站了,所以对其他数据也造成影响了。

那么我们能不能强行改造一下呢?

当然是可以的,我们另创建一个位来保存每个位置1的个数count,若每次删除,则将count减1。

如果count为0说明此时已经没有数据再占用这个位了,便可以置为0了,否则,count--即可.

当然这么做会增加了空间的消耗,会削弱布隆过滤器的优势,与其有这些空间存这个,不如用这些空间来降低一些误判率呢.

 哈希切分

先来看下面这个问题:

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?

哈希与位图的结合--布隆过滤器与哈希切分,哈希算法,布隆过滤器,C++,哈希切分

以上这张图已经说明了,我们可以将100G数据中的每个ip地址由哈希函数转为整数,再进行切分到不同的桶中,这样每个桶中都有对应的ip地址了。

那么我们该如何统计每个桶中的ip地址的个数呢?

当然是利用map进行统计,如果超过1G了呢?这里也会出现两种情况:

1.这个桶中不相同的ip很多,由于每次遇到不同的ip值,map都要进行插入,所以map统计不了。

2.这个桶中相同的ip很多,虽然有很多的ip,但是由于很多是相同的,所以直接在key对应的value上加1节课即可,并不会消耗空间。

直接使用map中的insert将每一个桶的元素插入到map中。

情况一:如果insert插入失败,说明空间不足,new节点失败,抛出异常。解决方法是换个哈希函数,递归再次对这个冲突桶进行切分。

情况二:map可以正常统计。

这样找到map中value值最高的即可。

2. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法

近似算法:将一个文件中的数据全部set进布隆过滤器中,然后分别用另一个文件的数据test比对,可以淘汰一定不是交集的部分。当然淘汰完剩下的那部分数据中,也会有非交集的存在。

精确算法:这个可以参考第一个问题的哈希切分方法。

思路是:利用相同的哈希函数(记住一定相同!)将两个文件的数据进行哈希切分,最后每个文件都会切分出许多小文件。然后我们分别比对下标相同的小文件,找出交集即可。

例如A文件切分出了A0,A1,A2...A999.

B文件切分出了B0,B1,B2....B999.

我们直接A0和B0,A1和B1,...A999和B999进行比较即可,因为两个文件使用了相同的哈希函数,所以对于两个文件相同的数据,经过切分后,一定会在编号相同的桶中.

然后再利用哈希表或set都可以,先将一个文件全部插入,经过去重后,再用另一个文件进行比对,找出交集即可。

 文章来源地址https://www.toymoban.com/news/detail-525634.html

到了这里,关于哈希与位图的结合--布隆过滤器与哈希切分的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构与算法】哈希—— 位图 | 布隆过滤器 | 哈希切割

    🐱作者:一只大喵咪1201 🐱专栏:《数据结构与算法》 🔥格言: 你只管努力,剩下的交给时间! 哈希是一种映射思想,这里再讲解两种应用哈希思想的数据结构。 问题: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数

    2024年02月02日
    浏览(57)
  • C++:布隆过滤器和哈希切分

    目录 一. 什么是布隆过滤器 二. 布隆过滤器的实现 2.1 数据插入函数set 2.2 判断数据是否存在函数test 2.3 布隆过滤器数据的删除 三. 哈希切分 在我之前的博客C++:使用位图处理海量数据_【Shine】光芒的博客-CSDN博客中,介绍了如何使用位图来处理海量数据,位图的特点为:

    2024年02月09日
    浏览(40)
  • 【C++】哈希(位图,布隆过滤器)

    今天的内容是哈希的应用:位图和布隆过滤器 目录 一、位图 1.位图概念 2.位图的应用 二、哈希切分 三、布隆过滤器 1.布隆过滤器的概念 2.布隆过滤器的应用 四、总结   今天的内容从一道面试题开始引入: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何

    2024年02月01日
    浏览(38)
  • C++哈希应用——位图布隆过滤器

    用哈希表存储用户记录,缺点是需要消耗较大的内存;用位图存储用户记录,缺点是位图一般处理整形,内容是字符串或者自定义类型就很勉强。基于以上,若将哈希和位图结合,称为布隆过滤器,会不会把上面的问题都解决了呢? 概念 布隆过滤器是一种概率型数据结构。

    2024年02月04日
    浏览(53)
  • 【C++】哈希位图和布隆过滤器

    哈希位图和布隆过滤器都是常用的概率数据结构,用于高效地判断一个元素是否存在于一个集合当中,但它们在实现方法和各自的优缺点上有所区别。 哈希位图 哈希位图(Hash Bitmap)是由一个位数组构成,每个元素(通常是一个整数)被映射到位数组中的某个位置。对于集合

    2024年02月08日
    浏览(50)
  • 哈希的应用--位图和布隆过滤器

    位图(Bitset)是一种数据结构,用于表示一组布尔值,其中每个元素通常对应于一个位或一个二进制值,可以存储0或1。位图在计算机科学和计算机工程中经常用于各种应用,特别是在位级别的标志、掩码和快速查找中。以下是位图的一些关键特点: 二进制表示 :位图中的每

    2024年02月08日
    浏览(53)
  • [C++]哈希应用之位图&布隆过滤器

               主厨:邪王真眼 主厨的主页:Chef‘s blog   所属专栏:c++大冒险        我们之前学习了哈希表,哈希表通过映射关系,实现了O(1)的复杂度来查找数据,哈希在实践中是一个非常重要的思想,今天要学习的就是哈希思想的两大应用:位图与布隆过滤器 给 40 亿个

    2024年04月15日
    浏览(41)
  • 【C++学习】哈希的应用—位图与布隆过滤器

    文章简介 : 在这篇文章中,你会学习到关于哈希思想的最常见的两个应用,也就是 位图 与 布隆过滤器 , 文章会讲解位图和布隆过滤器的概念,底层实现,对应的适应的场景,以及相关经典 海量数据面试题 及解析。 所谓位图,就是用每一位来存放某种状态,适用于 海量

    2024年04月14日
    浏览(61)
  • 【C++高阶(六)】哈希的应用--位图&布隆过滤器

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 哈希最常用的应用是unordered 系列的容器,但是当面对海量数据 如100亿个数据中找有没有100这 个数时,使用无序容器的话内存放不下 所以哈希

    2024年02月05日
    浏览(46)
  • C++进阶--哈希的应用之位图和布隆过滤器

    哈希是一种映射的思想。 先来看一道题:给40亿个不重复的无符号整数,没排序过。给一个无符号整数,如何 快速判断 一个数 是否在 这40亿个数中。 首先想到的解法可能有这几种: 解法1 :遍历40亿个数,O(N) 解法2 :先排序,快排O( N l o g 2 N Nlog_2N Nl o g 2 ​ N ),再利

    2024年02月22日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包