C++ 布隆过滤器哈希切割

news2025/1/11 5:55:10

前言

现实生活中,存在很多key_value的模型,我们可以使用哈希或者红黑树存储这些数据。但是二者只是内存的存储方式,无法处理海量数据。
海量数据的处理我们可以使用位图处理。但是位图的局限性是,其只能映射整型,对于浮点型,字符串无法解决。但是我们可以同哈希表那样,将浮点型,字符串转换成整型,然后再映射。这样就可以解决问题
这就是布隆过滤器的原理,其本质还是位图

在这里插入图片描述

文章目录

  • 前言
  • 一. 布隆过滤器
  • 二. 布隆过滤器的实现
  • 三. 哈希切割
  • 结束语

一. 布隆过滤器

布隆过滤器是 哈希+位图的结合

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

位图和哈希都是一个值映射一个位置,但是布隆过滤器需要映射字符串,字符串的组合非常之多,所以冲突的可能性很大,但是如果我们映射多个位置,那么误判的几率就降低很多了
如下图:
在这里插入图片描述

我们只需要使用多个哈希函数,将字符串转换成不同的整型映射即可。

但是,布隆过滤器可能存在误判的情况
因为我们查找一个字符串是否存在,是查看多个哈希函数转换成的整型地址,如果有一个是0,就代表不存在,因为如果存在,那这几个地址都是1。但是可能出现别的字符串已经映射到了这些地址,查找出来都是1。
所以布隆过滤器对于一个字符串存在是可能误判的,对于不存在是准确的。

  • 应用场景

新用户注册的昵称,就可以应用布隆过滤器。因为昵称是否误判,用户不知道,反之,电话号码就不能只用布隆过滤器,因为是否误判,用户可以知道。

布隆过滤器的实际使用正如其名,起到一个过滤器的作用。
如果一个数据使用布隆过滤器是不存在,是准确的,如果存在,再去数据库中查找,就保证了正确性。
因为数据库是在磁盘的,数据读取效率较低,先使用布隆过滤器刷选不存在的值,省去去数据库查找的开销。

二. 布隆过滤器的实现

上述我们讲到,布隆过滤器是具有多个哈希函数的位图,此位图与传统位图有所不同。
传统位图只能映射整型类型,整型可大可小,所以无论映射多少数据个数,位图的大小都必须开整型最大值。但是布隆过滤器映射的并不是整型,最常用的是字符型,所以并不需要像传统位图那样开空间。
但是这样就引出两个问题:开多大空间?要几个哈希函数?
很显然,过小的布隆过滤器很快所有的 bit 位均为 1,那么查询任何值都会返回“可能存在”,误判的几率很高。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。

哈希函数的个数越多则布隆过滤器 bit 位置位 1 的速度越快,因为一个字符串会映射多个位置,且布隆过滤器的效率越低;但是如果太少的话,那我们的误报率会变高。

详细分析见详解布隆过滤器的原理,使用场景和注意事项

文章中有这样一张图
在这里插入图片描述
该图展示了,在映射数据个数和空间一定是,越多的哈希函数,误判率更低
在这里插入图片描述
哈希函数也不是越多越好,还需要综合来看:
虽然哈希函数更多,误判率更低,但是每映射一个数据,都需要用多个哈希函数转换,那想必时间也消耗更多。所以不是单纯的哈希函数越多越好

接下来的实现,我们使用3个哈希函数,根据公式,开的空间大致是数据个数的4倍。


//哈希函数1
struct BKDRHash
{
	size_t operator()(const string& s)
	{
		// BKDR
		size_t value = 0;
		for (auto ch : s)
		{
			value *= 31;
			value += ch;
		}
		return value;
	}
};

//哈希函数2
struct APHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (size_t i = 0; i < s.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

//哈希函数3
struct DJBHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash += (hash << 5) + ch;
		}
		return hash;
	}
};

//三个仿函数
template<size_t N,class K=string,
class HashFunc1=BKDRHash,
class HashFunc2=APHash,
class HashFunc3=DJBHash>
class BloomFilter
{
public:
	//映射
	void set(const K&key)
	{
		size_t len = N * _X;

		size_t hash1 = BKDRHash()(key) % len;
		_bs.set(hash1);

		size_t hash2 = APHash()(key) % len;
		_bs.set(hash2);

		size_t hash3 = DJBHash()(key) % len;
		_bs.set(hash3);

		//可以将这三个哈希地址打印一下
		cout << hash1 << " " << hash2 << " " << hash3 << endl;
	}

	//查找
	bool test(const string&key)
	{
		size_t len = N * _X;

		//有一个比特位是0,就是不存在
		size_t hash1 = DJBHash()(key) % len;
		if (_bs.test(hash1) == false)
			return false;

		size_t hash2 = APHash()(key) % len;
		if (_bs.test(hash2) == false)
			return false;

		size_t hash3 = DJBHash()(key) % len;
		if (_bs.test(hash3) == false)
			return false;

		//都为1,可能存在,会误判
		return true;
	}
private:
	static const size_t _X = 4;//开空间的倍数
	bitset<N*_X>_bs;
};
  • 测试
    在这里插入图片描述

PS:布隆过滤器一般不支持删除,因为映射一个比特位的字符串可能不只一个,删除很可能影响其他的数据。
要支持删除,就需要使用多个位图,标识一个比特位被映射的次数,如果删除,只是减少一次映射次数,直到减为0,才是真正的删除。

但是这样判断数据存在的误判率就更高了,所以布隆过滤器一般都不支持删除


三. 哈希切割

  • 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?
    query是数据库的查询语句。可以理解为字符串
    100亿个query数据量很大,不能直接在内存中存储。所以我们可以将这个大文件切分成很多小文件,比如我们切分成1000个小文件,分为小文件Ai,和小文件Bi,而但是这样小文件的内容是不确定的。查找交集,需要比如A1和所有的小文件B查找交集,这样的效率实在太低了。
    所以我们可以在切分时做一些改动,我们还是切分成1000份,但是对于每一个query,我们可以进行一个哈希函数的转换,确定其要放置在哪个小文件。这样,A1只要和B1,A2只要和B2匹配交集即可。
    这就是哈希切割
    在这里插入图片描述

但是这样还会面临一个问题,因为本质也是哈希映射,就可能会有冲突,而冲突过多就可能导致小文件的大小膨胀

  1. 一个小文件有大量重复的数据
  2. 一个小文件有大量不同的数据

如何分辨这两种情况呢?如何解决这两种问题呢?

因为我们已经将文件分割小了,可以尝试使用unordered_set/set,依次存储该小文件的query。因为set可以对数据实现去重。而当内存满时,继续存储会抛bad_alloc异常
如果出现该异常,说明是情况2(有大量不同数据),因为去重没有达成效果。此时我们可以将小文件切分成更小的文件,继续哈希切割
而如果没有出现异常,说明是情况1(有大量重复数据),去重达到效果,那么该文件的哈希切割成功


  • 给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?与上题条件相同,如何找到top K的IP?

该题也类似,先通过哈希函数将IP地址转换成哈希地址,然后切分成小文件,然后依次处理小文件,使用unordered_map/map统计IP地址出现的次数。
如果抛异常,说明冲突太多,还需要继续切分
如果没有抛异常,那么统计成功。
然后汇总所有小文件出现次数最多的IP,最后使用priority_queue获取到TopK

结束语

本篇内容到此就结束了,感谢你的阅读!

如果有补充或者纠正的地方,欢迎评论区补充,纠错。如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

【k8s】Jenkins实现springcloud应用CI、CD实践 【三】【待写】

一、运行Jenkins流水线流程思路&#xff1a; 场景&#xff1a;java微服务应用&#xff0c; 单体仓库&#xff0c;多个微服务模块&#xff0c;&#xff08;并行构建、自动化构建、根据模块变更仅更新特定模块&#xff09; java、nodejsCI阶段 并行方式; 根据模块变…

港联证券|标普500指数年内涨逾9%,美股牛市已至?

今年以来&#xff0c;美国标普500指数累计上涨超过9%&#xff0c;这引发了一场关于美股牛市是否已经到来的辩论。 持悲观态度的摩根士丹利股票策略师威尔逊&#xff08;Michael Wilson&#xff09;警告称&#xff0c;最近的反弹不过是一种假象。而美国银行的萨勃拉曼尼亚&#…

四、数据仓库详细介绍(规范)

大家好&#xff0c;这是数据仓库系列的第三个话题&#xff0c;排序在架构之后、建模之前。为什么会提的这么靠前呢&#xff1f; 因为规范约束的是数仓建设的全流程&#xff0c;以及后续的迭代和运维。事实上&#xff0c;数仓规范文档&#xff0c;应该随着架构设计文档&#xf…

chatgpt赋能Python-python_lambdify

Python Lambdify: 一个方便的数学表达式转换工具 Python是一种广泛使用的编程语言&#xff0c;适用于各种领域&#xff0c;如数据科学、机器学习和科学计算等。在这些领域中&#xff0c;数学表达式起到了至关重要的作用&#xff0c;而Python Lambdify&#xff08;简称为“lamb…

计算机操作系统(慕课版)第四章课后题答案

一、简答题 1.什么是临界资源&#xff1f;什么是临界区&#xff1f; 临界资源&#xff1a;以互斥形式访问的资源&#xff1b;临界区&#xff1a;访问临界资源的代码。 2.同步机制应遵循的准则有哪些&#xff1f; 空闲让进&#xff1b;忙则等待&#xff1b;有限等待&#xff1b…

Windows本地快速搭建SFTP服务共享文件【外网访问】

文章目录 1. 搭建SFTP服务器1.1 下载 freesshd服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内网连接测试成功 3 使用cpolar内网穿透3.1 创建SFTP隧道3.2 查看在线隧道列表 4. 使用SFTP客户端&#xff0…

数据结构与算法-单调栈1

先介绍一下单调栈是什么 一种特别设计的栈结构&#xff0c;为了解决如下的问题&#xff1a; 给定一个可能含有重复值的数组arr&#xff0c;i位置的数一定存在如下两个信息 1&#xff09;arr[i]的左侧离i最近并且小于(或者大于)arr[i]的数在哪&#xff1f; 2&#xff09;arr[…

买法拍房注意事项

1、查清法拍房房屋属性。 竞拍前需查清楚法拍房的使用年限、能否办理房产证、土地性质等。 若土地为划拨属性&#xff0c;房屋可能需补缴土地出让金&#xff0c;该费用最好提前咨询当地不动产登记中心了解。 2、产权是否涉及二次过户。 二次过户指的是房屋已经过2次交易&…

苦卷一个月,P9大佬给我的Alibaba面试手册,终于成功踹开字节大门

怎么说呢&#xff0c;今年真的是寒气逼人啊&#xff01;在这个大环境下&#xff0c;裁员已经不算是特别的事情&#xff0c;粗暴裁员也许是未来一种趋势…在职的卷的起飞&#xff0c;离职的找不到好工作。 做点能做的&#xff1a;跑跑步骑骑车多锻炼&#xff1b;当当上面正版书…

分布式全局唯一id实现-2 springCloud-MyBatis-Plus集成百度分布式全局id(uid-generator)

前言&#xff1a;MyBatis-Plus 集成百度的uid-generator &#xff0c;实现业务实体在insert 实体时&#xff0c;可以自动获取全局id&#xff0c;完成数据保存&#xff1b; 1 uid-generator 全局id 生成的方式了解&#xff1a; Snowflake算法描述&#xff1a;指定机器 & 同…

如何避免孩子独自在家偷偷使用电脑?

电脑为我们的生活带来了极大的便利&#xff0c;但是对于孩子来说&#xff0c;过早的接触网络很容易影响其健康的成长。家长在家的话&#xff0c;还可以监督孩子&#xff0c;但如果家长出门了&#xff0c;该如何避免孩子偷偷使用电脑呢&#xff1f;其实方法很简单&#xff0c;只…

网络进阶学习:交换机二层

交换机二层 交换机的概念和作用交换机的划分交换机第二层的内容⭐第一部分&#xff1a;MAC地址⭐第二部分&#xff1a;逻辑链路控制子层⭐第三部分&#xff1a;介质访问控制子层⭐第四部分&#xff1a;交换机转发表⭐第五部分&#xff1a;VLAN⭐第六部分&#xff1a;STP 交换机…

Hudi系列25: Flink SQL使用checkpoint恢复job异常

文章目录 一. 通过Flink SQL将MySQL数据写入Hudi二. 模拟Flink任务异常2.1 手工停止job2.2 指定checkpoint来恢复数据2.3 整个yarn-session上的任务恢复 三. 模拟源端异常3.1 手工关闭源端 MySQL 服务3.2 FLink任务查看 FAQ:1. checkpoint未写入数据2. checkpoint 失败3. 手工取…

自然语言处理技术简介

长期以来&#xff0c;研究人员进行自然语言处理研究主要依赖各种机器学习模型&#xff0c;以及手工设计的特征&#xff0c;但这样做带来的隐患是由于语言信息被稀疏表征表示&#xff0c;会出现维度诅咒之类的问题。而随着近年来词嵌入&#xff08;低维、分布式表征&#xff09;…

港联证券|A股船舶板块景气反转即将到来

在经历了去年的爆发后&#xff0c;2023年的中国造船业仍然处在订单交付两旺的高度景气周期之中。 5月22日&#xff0c;中国船舶集团有限公司旗下沪东中华造船&#xff08;集团&#xff09;有限公司宣布交付全球最大级别24116TEU超大型集装箱船系列3号船“地中海吉玛”号。据报道…

3D 对象转换器应该如何将 OBJ 转换为 FBX ?

Aspose.3D 是一个功能丰富的游戏软件和计算机辅助设计&#xff08;CAD&#xff09;的API&#xff0c;可以在不依赖任何3D建模和渲染软件的情况下操作文档。API支持Discreet3DS, WavefrontOBJ, FBX (ASCII, Binary), STL (ASCII, Binary), Universal3D, Collada, glTF, GLB, PLY…

SpringMVC框架理解

JavaEE体系结构包括四层&#xff0c;从上到下分别是应用层、Web层、业务层、持久层。Struts和SpringMVC是Web层的框架&#xff0c;Spring是业务层的框架&#xff0c;Hibernate和MyBatis是持久层的框架。 为什么要使用SpringMVC&#xff1f; 很多应用程序的问题在于处理业务数据…

一对一项目指导,在线购物网站webform+SQLServer技术架构

我是Tom老师&#xff0c;10开发经验&#xff0c; 我先后在携程网、陆金所&#xff0c;两家互联网和金融行业领头公司 担任高级开发工程师&#xff0c; 技术深厚&#xff0c;开发经验丰富&#xff0c;认真负责。 我现在专门做一对一编程辅导。 希望我的专业辅导&#xff0c;…

02数字图像基础

文章目录 2数字图像基础2.4图像取样和量化2.4.4图像内插 2.5像素间的一些基本关系2.5.1相邻像素2.5.2邻接性、连通性、区域和边界2.5.3距离度量 2.6 数字图像处理2.6.1阵列和矩阵操作2.6.2线性操作和非线性操作2.6.3算术操作2.6.5空间操作2.6.6向量与矩阵操作2.6.7图像变换2.6.…

架构演变之路

一)单机架构: 一)定义:应用服务和数据库服务器共用一台服务器&#xff0c;所有的服务被部署到一台服务器上面 蓝色的就是我们写的JAVA代码用户服务负责用户的登录和注册&#xff0c;商品服务用于商品的购买和交易&#xff0c;交易模块用于用户的下单和购买&#xff0c;在数据库…