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

news2024/10/6 22:33:01

目录

一. 什么是布隆过滤器

二. 布隆过滤器的实现

2.1 数据插入函数set

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

2.3 布隆过滤器数据的删除

三. 哈希切分


一. 什么是布隆过滤器

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

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

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

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

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

图1.1 布隆过滤器设计思想

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

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

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

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

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

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

图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,那会影响到其它的值,让其它存在的值被误判为不存在,这是布隆过滤器所不允许的。

图2.2 布隆过滤器的误删除问题

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

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

图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,如遇到相同值,就是小文件交集。这样还可以实现去重功能。

图3.1 采用哈希切分查找大文件交集的方法

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

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

图3.2 哈希切分思想处理海量数据topK问题

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

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

相关文章

【LinuxShell】linux防火墙之firewalld防火墙

文章目录 前言一、firewalld概述1. 概念2. firewalld和iptables的关系 二、firewalld网络区域1. firewalld区域的概念2. firewalld预定义区域3. firewalld数据包的处理3.1 firewalld数据处理流程3.2 firewalld检查数据包的源地址的规则3.3 总结 三、firewalld防火墙的配置方法1…

“GPT+医疗健康”:给予医疗领域新机遇

现如今&#xff0c;GPT十分火热。随着人们对健康医疗的关注越来越热切&#xff0c;GPT已逐渐成为健康医疗领域的重要角色之一。GPT可以用于许多医疗语境中&#xff0c;如医学咨询、病症诊断、健康建议、在线问诊、患者教育、健康数据跟踪等。 GPT是一种基于深度学习的自然语言处…

结构体-C语言

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C知识系统分享》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c…

【Python办公自动化】python实现将图片插入到word中指定位置并将word转换为图片

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、…

垃圾站养殖场除臭杀菌解决方案

养殖场和垃圾站都会产生大量的有机废气和垃圾&#xff0c;这些废气和垃圾会产生难闻的臭味&#xff0c;影响周围环境和居民健康。这些地方又是病菌和细菌的滋生地&#xff0c;这些细菌和病菌会对人类和动物的健康造成威胁。除臭杀菌系统可以杀灭这些细菌和病菌&#xff0c;也可…

换个思维方式,你离网工天花板会更近一点

大家好&#xff0c;我是许公子。 收到老杨的邀请&#xff0c;我正式加入网络工程师俱乐部了&#xff0c;未来会给你分享更多网工硬核内容。 和老杨聊天的过程中&#xff0c;我想起了在刚入社会一两年&#xff0c;我去参加了一个高中同学聚餐。 里面有自主创业的&#xff0c;…

软件测试被00后整顿职场了?

00后带来的压力 公司一位工作3年的老油条工资还没有刚来的00后高&#xff0c;她心中不平&#xff0c;对这件事情有不小的怨气&#xff0c;她觉得自己来公司三年了&#xff0c;三年内迟到次数都不超过5次&#xff0c;每天勤勤恳恳&#xff0c;要加班的时候也愿意加班&#xff0…

Python竖版大屏 | 用pyecharts开发可视化的奇妙探索

你好&#xff01;我是马哥python说&#xff0c;一枚10年程序猿&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff0c;正在试错用pyecharts开发可视化大屏的非常规排版。 以下&#xff0c;我用8种ThemeType展示的同一个可视化数据大屏。 1、SHINE主题 2、LIGHT主题 3、MACARO…

手撕代码——任意奇数分频

手撕代码——任意奇数分频 一、奇数分频器原理与设计 在上文《手撕代码——任意偶数分频》中&#xff0c;我们编写任意偶数分频的Verilog代码&#xff0c;对时钟进行偶数分频&#xff0c;只需要用到时钟的上升沿或者下降沿即可&#xff0c;而要进行N倍奇数分频&#xff0c;需要…

修改Allure报告窗口标题,Overview的标题文案,环境配置,左上角LOGO

前言 如下图所示&#xff1a; 一、修改Allure报告窗口标题 Allure-html测试报告的窗口标题保存在&#xff1a;allure-html目录下的index.html文件 写个 set_windows_title 方法&#xff0c;并在 run.py 的执行文件去调用即可修改&#xff08; 在html报告生成后&#xff09…

研报精选230522

目录 【行业230522东亚前海证券】新能源行业深度报告&#xff1a;政策东风与海外需求共振&#xff0c;充电桩迎新一轮增长周期 【行业230522西南证券】人工智能专题研究&#xff1a;AIGC投资框架 【行业230522国信证券】传媒互联网行业周报&#xff1a;OpenAI推出移动版及网页端…

文献笔记——A brief introduction to distributed systems(分布式系统)

本文主要讨论了分布式系统。作者提供了关于分布式系统的概述&#xff0c;是一份很好的新手教程。 Fig.1 大纲 在论文的第一部分&#xff0c;作者简要回顾了计算机的演变&#xff0c;指出了分布式系统的两个技术基础&#xff1a;性能强大的微处理器的发展和高速计算机网络的发明…

OpenCV:CMake 产生 VS2019 项目和解决方案

CMake 是一个跨平台的自动化编译程序&#xff0c;它用于管理代码的构建过程。使用 CMake 可以简化跨平台项目的构建和移植&#xff0c;提供简单而强大的语法来描述构建过程&#xff0c;并生成多种不同的构建系统&#xff0c;如 GNU Make、Ninja 和 Visual Studio。因为 CMake 具…

8年测试总结,性能测试问题大全,这些问题你应该认清的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 响应时间VS吞吐量…

18-02 数据库设计核心要点

概念结构设计 通过对用户需求进行综合、归纳和抽象&#xff0c;形成独立于具体数据库管理系统的概念模型把需求分析阶段得到的应用需求&#xff0c;抽象成概念模型连接现实世界和信息世界的桥梁好的概念结构设计 能真实、充分的反映现实世界要易于理解要易于修改 基本概念 …

kubeadm部署k8s 1.26.0版本高可用集群

1.前言 本次搭建使用centos7.9系统&#xff0c;并且使用haproxykeepalived作为高可用架构软件&#xff0c;haproxy实现k8s集群管理节点apiserver服务的负载均衡以实现集群的高可用功能&#xff0c;keepalived保障了hapxoy的高可用&#xff0c;容器引擎使用docker&#xff0c;需…

迁移iceberg:一.查看所需要的资源。

一&#xff1a;内存&#xff0c;CPU&#xff0c;核数&#xff0c;线程&#xff0c;硬盘。 1. cpu&#xff0c;核素&#xff0c;线程。 cpu cpu就相当于人类的大脑&#xff0c;是处理数据的地方。 cpu由以下三个组成。 控制器。由控制单元、指令译码器、指令寄存器组成。运算…

戴尔 dell Inspiron3670电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板B360 处理器i5-9400已驱动 内存8GB已驱动 硬盘KBG40ZNS256G NVMe KIOXIA 256GB ST1000DM010 1TB已驱动 显卡UHD630(1.05GHZ)已驱动 声卡Realte…

Node模拟慢接口

为了快速搭建一个后台服务&#xff0c;并模拟慢接口&#xff0c;我们选择 Koa 这个轻量的 Node 框架。 快速开始 Koa 使用起来非常方便&#xff0c;只需要&#xff1a; 新建项目文件夹&#xff1a;mkdir koa-server创建 package.json&#xff1a;npm init -y安装 Koa&#x…

夏季门店做好这3点,销量翻一番!

现在正值5月末&#xff0c;天气开始炎热起来。在酷热的夏日&#xff0c;很多人都只想呆在家里吹空调刷手机&#xff0c;外出消费的人数开始变少。 面对越来越炎热的天气&#xff0c;我们这些做实体店生意的该如何应对呢&#xff1f;想要在夏季客流不减反增&#xff0c;销量翻倍…