C++:布隆过滤器和哈希切分

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

目录

一. 什么是布隆过滤器

二. 布隆过滤器的实现

2.1 数据插入函数set

2.2 判断数据是否存在函数test

2.3 布隆过滤器数据的删除

三. 哈希切分


一. 什么是布隆过滤器

在我之前的博客C++:使用位图处理海量数据_【Shine】光芒的博客-CSDN博客中,介绍了如何使用位图来处理海量数据,位图的特点为:

  • 速度快,节省空间。
  • 采用直接定值法,不存在哈希冲突。
  • 只适用于整形数据。

为了解决位图只适用于整形数据的问题,布隆过滤器被提了出来,是哈希表和位图结合的一种数据结构,主要用于处理海量字符串数据。

布隆过滤器的设计思想为:给定一个关键值Key,通过哈希函数,将其转换为size_t类型的数据,记为hashi,这里的hashi对应一个比特位,如果Key存在,它对应的二进制位就是1。我们可以认为,布隆过滤器的底层也是通过位图来实现的,是对位图的封装。

布隆过滤器和位图的不同在于:位图直接使用整形数据映射比特位,属于直接定值法,而布隆过滤器要对整形数据进行进一步转换(一般使用除留余数法)后映射到对应二进制位。

C++:布隆过滤器和哈希切分
图1.1 布隆过滤器设计思想

但是,如果只给定一个哈希函数,就很容易存在哈希冲突,从而导致误判:

  • 如果判定为存在,那么有可能是误判,因为即使给定的key值不在,它也可能与某个存在的关键值冲突。
  • 如果判定为不存在,则不可能是误判。

布隆过滤器的误判不可能完全避免,但是可以采取一定的优化措施,来降低误判率。

  • 让一个值映射多个比特位可以降低误判概率,从理论上讲,一个值映射的比特位越多,误判概率越低,但是消耗的空间也越大。
C++:布隆过滤器和哈希切分
图1.2 布隆过滤器的优化(一个值映射三个比特位)

布隆过滤器具有很强的实际应用价值,其在实际应用中分为允许误判和不允许误判两种情况:

  • 不允许误判:如黑名单通缉系统,所有的黑名单人员信息都被存储在远端数据库,而前端存储了数据库的布隆过滤器信息。当前端接收到一个人的信息要判断它是否在黑名单时,先走前端的布隆过滤器,如果布隆过滤器返回的结果为不在,那么不可能误判,直接返回。如果布隆过滤器的结果为在,那么就需要通过网络连接远端数据库,在数据库中匹配信息,判断是否是误判。
  • 允许误判:注册账号时,判断用户自定义的用户名是否和已有用户名冲突,如果冲突要求用户重新定义用户名。这里允许误判,所有直接走近端的布隆过滤器即可,无需再通过远端的数据库确认是否误判。
C++:布隆过滤器和哈希切分
图1.3 不允许误判时布隆过滤器的工作机制

二. 布隆过滤器的实现

假设布隆过滤器共设置了3个哈希函数,分别记为Hash1、Hash2、Hash3,即:1个key值对应3个比特位。 布隆过滤器类有一个成员变量_bst,自定义类型位图,N为待插入数据的个数。

代码2.1:布隆过滤器声明

//布隆过滤器(一般用于字符串)
//Hash1/2/3的默认值为三个字符串哈希函数,这是为了降低误判概率
template<size_t N, class K = std::string, class Hash1 = BKDRHash, class Hash2 = APHash, class Hash3 = DJBHash>
class BloomFilter
{
public:
	void set(const K& key);   //数据插入函数
	bool test(const K& key);  //数据查找函数

private:
	static const size_t ratio = 5;   //比例因子
	zhang::bitset<N * ratio> _bst;   //位图
};

2.1 数据插入函数set

获取到要插入的key数据(一般为string)后,通过三个哈希函数将key转换为3个不同的整形数据,将三个整形位置对应的比特位都置为1即可。

C++:布隆过滤器和哈希切分
图2.1 布隆过滤器数据插入操作

代码2.2:set函数

	//一个关键值key对应三个不同的哈希函数,有三个不同的位置
	//set函数将三个对应的bit位全部置1
	void set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (N * ratio);
		size_t hash2 = Hash2()(key) % (N * ratio);
		size_t hash3 = Hash3()(key) % (N * ratio);

		_bst.set(hash1);
		_bst.set(hash2);
		_bst.set(hash3);
	}

2.2 判断数据是否存在函数test

检查key值对应的n个bit位是否全部为1,如果有一个是0,则表明key不存在。注意,如果判定为存在,那么可能是由于哈希冲突造成的,可能是误判。

代码2.3:test函数

	bool test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (N * ratio);
		if (!_bst.test(hash1))
			return false;

		size_t hash2 = Hash2()(key) % (N * ratio);
		if (!_bst.test(hash2))
			return false;

		size_t hash3 = Hash3()(key) % (N * ratio);
		if (!_bst.test(hash3))
			return false;

		//三个哈希函数映射的二进制位都是1,表示存在
		return true;
	}

2.3 布隆过滤器数据的删除

一般而言,布隆过滤器是不支持数据删除的,但是,也并非不可以实现。如果采用一般形式的一个key对应多个比特位的布隆过滤器,那么直接在删除key时将它对应的比特位置0,那会影响到其它的值,让其它存在的值被误判为不存在,这是布隆过滤器所不允许的。

C++:布隆过滤器和哈希切分
图2.2 布隆过滤器的误删除问题

我们可以通过将每个bit位扩展为一个小计数器,来解决数据删除问题。这样原本一个Hash(key)计算值由映射到一张位图中的一个bit位,变为映射到多种位图中的多个bit位。假设布隆过滤器中有两张位图,两个位图特定位置中的两个bit为表示这个位置被映射到的次数。11表示3次,10表示2次,01表示一次。删除数据时,计数器的值-1即可。

但是,布隆过滤器如果支持删除,必然会引起空间消耗量的上升,却依旧无法完全避免误删除问题,布隆过滤器最大的优势之一就是空间消耗少,如果支持删除这一优势就会大打折扣,因此一般不需要布隆过滤器支持数据删除。

C++:布隆过滤器和哈希切分
图2.3 布隆过滤器数据删除逻辑

三. 哈希切分

本文从两个海量数据处理问题入手,讲述哈希切分。

问题1:给定两个含有100亿个query(字符串)的文件,如何精确查找两个文件的交集?

我们假设一个query占用20bytes的空间,那么100亿个query就占用2000亿bytes的空间,也就是200G,显然,内存无法容纳这么多数据。

处理大文件的一种常用方法是将大文件均分为N个小文件,我们假设将问题中的一个文件均分为1000个小文件,将一个大文件切分出来的每个小文件,与另一个文件中的每个小文件进行比较,查找交集,这样确实可以找出两个大文件的交集,但效率十分低下。

为了高效查找大文件交集,我们采用哈希切分的方法。假设两个大文件分别叫做A和B,并将每个大文件切分为1000个小文件,从0~999对每个小文件进行编号,读取A和B文件中的每个query,根据i=Hash(query)%1000,将query放入对应编号的小文件中。这样可以保证相同的query被放入相同编号的小文件中,最终只需要比较大文件A和B编号相同的小文件找交集即可。

查找交集的方法:将两个小文件中的query放入到两个set中去,从begin()位置开始遍历两个set,如遇到相同值,就是小文件交集。这样还可以实现去重功能。

C++:布隆过滤器和哈希切分
图3.1 采用哈希切分查找大文件交集的方法

问题2:给定一个超过100G的日志文件,里面存储了若干IP地址,如何找出出现次数最多的K个IP地址(topK问题)

这里也要采用哈希切割的思想解决问题。将Log大文件切分为N个小文件,编号从0~N,根据i=Hash(IP)%N,计算每个IP应该放入到哪个小文件中,这样可以保证相同的IP在相同的小文件中。完成切分后,使用map<string, int>对每个小文件中的每个IP出现的次数进行统计,然后使用小堆结构,统计出现次数最多的K个IP。文章来源地址https://www.toymoban.com/news/detail-490064.html

C++:布隆过滤器和哈希切分
图3.2 哈希切分思想处理海量数据topK问题

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

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

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

相关文章

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

    上一章讲了位图,我们知道了在海量数据中查找一个数是否存在,可以用每一个比特位标识。 但是位图只能处理整数,要是字符串或者其它的呢,位图便无法处理了,这个时候便需要用到布隆过滤器了. 目录 布隆过滤器提出 布隆过滤器概念 布隆过滤器的实现以及最优值  哈

    2024年02月12日
    浏览(37)
  • 【C++】哈希与布隆过滤器

    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘 。 🛸 C++专栏 : C++内功修炼基地 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真

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

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

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

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

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

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

    2024年02月08日
    浏览(50)
  • C++ 哈希的应用【布隆过滤器】

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2022 版本 17.6.5 注册账号是进行网络冲浪的第一步操作,而拥有一个具有个性且独一无二的用户昵称是非常重要的,很多人在填写昵称时,常常会看到 此昵称已存在 的提示,系统是如何快速知道当前昵称

    2024年02月14日
    浏览(44)
  • 【C++】哈希应用之布隆过滤器

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.布隆过滤器的提出 2.布隆过滤器的概念 3.布隆过滤器的模拟实现 3.1布隆

    2024年03月27日
    浏览(38)
  • 【C++】哈希的应用——布隆过滤器

    我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。问题来了,新闻客户端推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选

    2023年04月22日
    浏览(87)
  • [C++]哈希应用之位图&布隆过滤器

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

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

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

    2024年04月14日
    浏览(61)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包