【数据结构】哈希应用-布隆过滤器

news2024/9/25 2:26:36

目录

1、布隆过滤器的概念

2、布隆过滤器误判率推导

3、代码实现

3.1 Set

3.2 Test

4、布隆过滤器的删除

5、布隆过滤器的应用


1、布隆过滤器的概念

有⼀些场景下⾯,有⼤量数据需要判断是否存在,⽽这些数据不是整形,那么位图就不能使⽤了,使⽤红⿊树/哈希表等内存空间可能不够。这些场景就需要布隆过滤器来解决。
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 ⼀种紧凑型的、⽐较巧妙的概率型数据结构,特点是⾼效地插⼊和查询,可以⽤来告诉你 “某样东西⼀定不存在或者可能存在”,它是⽤多个哈希函数,将⼀个数据映射到位图结构中。此种⽅式不仅可以提升查询效率,也可以节省⼤量的内存空间。
布隆过滤器的思路就是把key先映射转成哈希整型值,再映射⼀个位,如果只映射⼀个位的话,冲突率会⽐较多,所以可以通过多个哈希函数映射多个位,降低冲突率
布隆过滤器这⾥跟哈希表不⼀样,它⽆法解决哈希冲突的,因为他压根就不存储这个值,只标记映射的位。它的思路是尽可能降低哈希冲突。判断⼀个值key在是不准确的,判断⼀个值key不在是准确的。

像这幅图中一个数据映射了3个位,只有当3个位都是1时,才认为这个数据是存在的,注意此时仍然有可能是不存在的,即是存在误判的,这里的猪八戒就是存在的。当3个位置中有一个位置是0时,这个数据就是不存在的,这是一定的,这里的孙悟空就是不存在的。

2、布隆过滤器误判率推导

这里是利用数学就行推导

3、代码实现

布隆过滤器底层使用的是上一节的位图,不过这里需要增加仿函数将其他类型映射为整型 

struct HashFuncBKDR
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto ch : s)
		{
			hash *= 31;
			hash += ch;
		} 
		return hash;
	}
};
struct HashFuncAP
{
	// 由Arash Partow发明的⼀种hash算法。
	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;
	}
};
struct HashFuncDJB
{
	// 由Daniel J. Bernstein教授发明的⼀种hash算法。
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash = hash * 33 ^ ch;
		} 
		return hash;
	}
};
template<size_t N,
	size_t X = 5,
	class K = std::string,
	class Hash1 = HashFuncBKDR,
	class Hash2 = HashFuncAP,
	class Hash3 = HashFuncDJB>
class BloomFilter
{
public:

private:
	static const size_t M = N * X;
	cxf::bitset<M> _bs;
};

这里设计3个哈希函数的布隆过滤器。模板参数N是布隆过滤器开的位数,X是误导率推导中的m / n,根据前面的计算,当哈希函数是3个时,m / n是5则误导率最低的,K是数据的类型,默认是string,后面3个参数是仿函数,将string映射为整型,3个仿函数对同一个string映射的结果需要不同。注意:这里的N = n,X = m / n,所以虽然传过来需要开一个N位的布隆过滤器,但是实际上的位图需要开N * X个位的位图

3.1 Set

将映射到的位置全部置为1

void Set(const K& key)
{
	// 计算在不同仿函数下映射到的位置
	size_t hash1 = Hash1()(key) % M;
	size_t hash2 = Hash2()(key) % M;
	size_t hash3 = Hash3()(key) % M;
	// 将映射到的位置设置为1
	_bs.set(hash1);
	_bs.set(hash2);
	_bs.set(hash3);
}

3.2 Test

检查一个值是否在布隆过滤器中。此时需要检查映射到的位置是否全为1,若全为1,在,此时可能误判,若有1个或1个以上位置不为1,则不在,此时没有误判

bool Test(const K& key)
{
	size_t hash1 = Hash1()(key) % M;
	if (!_bs.test(hash1)) // 如果映射到的这个位置是0,就返回false,此时没有误判
		return false;
	size_t hash2 = Hash2()(key) % M;
	if (!_bs.test(hash2)) // 如果映射到的这个位置是0,就返回false,此时没有误判
		return false;
	size_t hash3 = Hash3()(key) % M;
	if (!_bs.test(hash3)) // 如果映射到的这个位置是0,就返回false,此时没有误判
		return false;

	return true; // 映射到的位置全为1,则返回true,此时可能存在误判
}

此时可以就行测试

void TestBloomFilter()
{
	BloomFilter<10> bf;
	bf.Set("猪八戒");
	bf.Set("孙悟空");
	bf.Set("唐僧");
	cout << bf.Test("猪八戒") << endl;
	cout << bf.Test("孙悟空") << endl;
	cout << bf.Test("唐僧") << endl;
	cout << bf.Test("沙僧") << endl;
	cout << bf.Test("猪八戒1") << endl;
	cout << bf.Test("猪戒八") << endl;
}

结果是1 1 1 0 0 0,是没有问题的

struct HashFuncBKDR
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto ch : s)
		{
			hash *= 31;
			hash += ch;
		} 
		return hash;
	}
};
struct HashFuncAP
{
	// 由Arash Partow发明的⼀种hash算法。
	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;
	}
};
struct HashFuncDJB
{
	// 由Daniel J. Bernstein教授发明的⼀种hash算法。
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash = hash * 33 ^ ch;
		} 
		return hash;
	}
};
template<size_t N,
	size_t X = 5,
	class K = std::string,
	class Hash1 = HashFuncBKDR,
	class Hash2 = HashFuncAP,
	class Hash3 = HashFuncDJB>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		// 计算在不同仿函数下映射到的位置
		size_t hash1 = Hash1()(key) % M;
		size_t hash2 = Hash2()(key) % M;
		size_t hash3 = Hash3()(key) % M;
		// 将映射到的位置设置为1
		_bs.set(hash1);
		_bs.set(hash2);
		_bs.set(hash3);
	}
	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % M;
		if (!_bs.test(hash1)) // 如果映射到的这个位置是0,就返回false,此时没有误判
			return false;
		size_t hash2 = Hash2()(key) % M;
		if (!_bs.test(hash2)) // 如果映射到的这个位置是0,就返回false,此时没有误判
			return false;
		size_t hash3 = Hash3()(key) % M;
		if (!_bs.test(hash3)) // 如果映射到的这个位置是0,就返回false,此时没有误判
			return false;

		return true; // 映射到的位置全为1,则返回true,此时可能存在误判
	}
private:
	static const size_t M = N * X;
	cxf::bitset<M> _bs;
};

4、布隆过滤器的删除

布隆过滤器默认情况下是不支持删除的

在上面这幅图中,猪八戒和孙悟空都在布隆过滤器中,如果此时将猪八戒删除,也就是将猪八戒映射到的3个位都置成0,此时孙悟空也被删除了

解决⽅案:可以考虑计数标记的⽅式,⼀个位置用多个位标记,记录映射这个位的计数值,删除时,仅仅减减计数,那么就可以某种程度⽀持删除。但是这个⽅案也有缺陷,如果⼀个值不在布隆过滤器中(Test返回结果是真,也就是出现了误判),我们去删除,减减了映射位的计数,那么会影响已存在的值,也就是说,⼀个确定存在的值,可能会变成不存在,这⾥就很坑。当然也有⼈提出,我们可以考虑计数⽅式⽀持删除,但是定期重建⼀下布隆过滤器,这样也是⼀种思路。

5、布隆过滤器的应用

首先,我们先来分析一下布隆过滤器的优缺点

优点:效率⾼,节省空间,相⽐位图,可以适⽤于各种类型的标记过滤
缺点:存在误判(在是不准确的,不在是准确的),不好⽀持删除 

布隆过滤器的一些应用

爬⾍系统中URL去重:
在爬⾍系统中,为了避免重复爬取相同的URL,可以使⽤布隆过滤器来进⾏URL去重。爬取到的URL可以通过布隆过滤器进⾏判断,已经存在的URL则可以直接忽略,避免重复的⽹络请求和数据处理。
垃圾邮件过滤:
在垃圾邮件过滤系统中,布隆过滤器可以⽤来判断邮件是否是垃圾邮件。系统可以将已知的垃圾邮件的特征信息存储在布隆过滤器中,当新的邮件到达时,可以通过布隆过滤器快速判断是否为垃圾邮件,从⽽提⾼过滤的效率。
预防缓存穿透:
在分布式缓存系统中,布隆过滤器可以⽤来解决缓存穿透的问题。缓存穿透是指恶意⽤⼾请求⼀个不存在的数据,导致请求直接访问数据库,造成数据库压⼒过⼤。布隆过滤器可以先判断请求的数据是否存在于布隆过滤器中,如果不存在,直接返回不存在,避免对数据库的⽆效查询。
对数据库查询提效:
在数据库中,布隆过滤器可以⽤来加速查询操作。例如:⼀个app要快速判断⼀个电话号码是否注册过,可以使⽤布隆过滤器来判断⼀个⽤⼾电话号码是否存在于表中,如果不存在,可以直接返回不存在,避免对数据库进⾏⽆⽤的查询操作。如果在,再去数据库查询进⾏⼆次确认。

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

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

相关文章

【学习笔记】Day 6

一、进度概述 1、《地震勘探原理》第二章 2、“DenseNet” 周报分享 二、详情 1、《地震勘探原理》第二章 注&#xff1a;本来的打算是逐章整理&#xff0c;但是在听老师指导后&#xff0c;明晰了学习目的。故学习方法更改为侧重 “刷” 。不求一遍全弄懂&#xff0c…

实验8-2-4 使用函数实现字符串部分复制

本题要求编写函数&#xff0c;将输入字符串t中从第m个字符开始的全部字符复制到字符串s中。 函数接口定义&#xff1a; void strmcpy( char *t, int m, char *s );函数strmcpy将输入字符串char *t中从第m个字符开始的全部字符复制到字符串char *s中。若m超过输入字符串的长度…

[Vue]Vue3从入门到精通-综合案例分析

一.Vue是什么&#xff1a; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式的框架 以下的内容是自里向外的 声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite Vue的两种使用方式&#xff1a; Vue核心包开发-&…

好用高性价比蓝牙耳机有哪些?万人点赞四大高性价比耳机推荐

如今&#xff0c;市面上蓝牙耳机种类繁多&#xff0c;而面对市场上众多百元内的耳机品牌和型号&#xff0c;怎么选才能够选到一款音质好&#xff0c;续航久的蓝牙耳机呢&#xff0c;到底什么样的蓝牙耳机更适合自己&#xff0c;那么好用高性价比蓝牙耳机有哪些&#xff1f;接下…

理解Spring框架2:容器IOC

理解Spring框架2&#xff1a;容器IOC (qq.com)

如何计算UDP校验和

在了解 UDP 校验和的时候&#xff0c;发现资料很少&#xff0c;如果看教材的话&#xff0c;一定看到过下面这两张图&#xff0c;但是又看不懂&#xff0c;加上解释之后也难懂&#xff1a; 本文先说具体怎么算的&#xff0c;再说一些细节&#xff0c;过程中顺带解释一下这两个图…

浅析中国蚁剑的木马加密流量

简介 在蓝帽杯 2022 初赛中&#xff0c;domainhacker 的流量分析题目聚焦于中国蚁剑这款 webshell 管理工具的流量特征。通过对比赛提供的数据包进行解析&#xff0c;本文将深入分析蚁剑在连接木马时产生的加密流量。 公司安全部门&#xff0c;在流量设备中发现了疑似黑客入侵的…

微信小程序开发【从0到1~入门篇4】

如果您没有看我上一篇文章&#xff0c;建议返回阅读&#xff1a; 微信小程序开发【从0到1~入门篇3】 这篇文章进入基础增强阶段&#xff0c;通过对这篇文章的学习&#xff0c;你将学会以下内容 ① 能够创建并引用组件 ⚫ 全局引用、局部引用、usingComponents ② 能够知道如何…

Unity初识

1&#xff1a;下载Unity Hub 下载地址&#xff1a;Unity官方下载_Unity最新版_从Unity Hub下载安装 | Unity中国官网 建议直接使用unity hub因为支持比较全面&#xff0c;适合新手 有中文 管理 编辑器等等功能支持 下载安装不过多介绍 2&#xff1a;Unity Hub汉化 因为我…

Unity Console 窗口输出对齐

起因&#xff1a;做了个工具在console窗口罗列一些信息&#xff0c;基本结构是 [ 文件名 &#xff1a;行号 ]&#xff0c;因为文件&#xff0c;行号长度不一&#xff0c;想要做到如下效果。 初步尝试&#xff0c;用以下方法&#xff1a; string format "{0,-10} …

凯伦股份子公司中标中建八局发展建设分公司年度多项工程集采

近日&#xff0c;凯伦股份旗下全资子公司——苏州凯瑞伦建筑工程有限公司凭借其卓越的专业素养和服务能力&#xff0c;顺利中标中国建筑第八工程局有限公司发展建设分公司-北京分公司2024年度-北京、天津、河北、内蒙等区域防水工程集采。 中国建筑第八工程局有限公司发展建设分…

书生大模型实战营-入门关卡-Linux 前置基础

任务&#xff1a;Tutorial/docs/L0/Linux at camp3 InternLM/Tutorial GitHub 完成&#xff1a;

长在客户审美点上的可视化大屏,大概率就是这个样子。

要想使可视化大屏长在客户审美点上&#xff0c;需要具备以下特征&#xff1a; 布局合理&#xff1a;有良好的整体结构和布局&#xff0c;各个元素之间的关系清晰&#xff0c;避免视觉上的混乱和杂乱无章感。信息展示清晰有序&#xff0c;重点突出&#xff0c;能够让客户快速找…

Granger-因果检验及 Stata 具体操作步骤

目录 一、文献综述 二、理论原理 三、实证模型 四、程序代码及解释 五、代码运行结果 一、文献综述 Granger 因果检验作为一种重要的时间序列分析方法&#xff0c;在众多学科领域中都发挥着关键作用&#xff0c;并引发了广泛的研究和应用。 在宏观经济学领域&#xff0c;学…

探秘C# LINQ元素运算:原理阐释与实践指南

文章目录 一、LINQ元素运算符概述二. ElementAt 和 ElementAtOrDefault三. First 和 FirstOrDefault四. Last 和 LastOrDefault五. Single 和 SingleOrDefault六. Where 和 Select七、实际应用场景示例总结 LINQ&#xff08;Language-Integrated Query&#xff09;是C#中强大且…

Linux基础IO——重定向与文件缓冲区

文章目录 重定向重定向的系统调用C语言中的FILE结构体 文件缓冲区C语言缓冲区 重定向 我们在学习Linux的基本内容时候&#xff0c;知道>> >都可以用来表示重定向&#xff0c;那么重定向的本质是什么呢&#xff0c;其实就是更改了标号为1的文件描述符 1表示标准输出&…

虚实共生:数字孪生技术引领设施农业新未来

在全球人口持续增长和气候变化日益严峻的背景下,设施农业正面临前所未有的挑战和机遇。如何在有限的资源条件下提高作物产量、质量和生产效率,成为困扰农业从业者的核心问题。随着人工智能、物联网和大数据等新兴技术的快速发展,数字化转型为设施农业带来了新的希望。其中,数字…

如何为树莓派添加人工智能超能力!

Raspberry Pi AI 套件价格实惠&#xff0c;安装简单&#xff0c;只要你能找到一个。 Adrian Kingsley-Hughes/ZDNET ZDNET 的关键要点 Raspberry Pi 基金会发布了适用于 Pi 5 的 Raspberry Pi AI 套件&#xff0c;但供应情况并不稳定。在撰写本文时&#xff0c;我在亚马逊和芝…

跟《经济学人》学英文:2024年08月03日这期 What is the point of industry awards?

What is the point of industry awards? Booze, sweat and plexiglass booze&#xff1a;美 [buz] 酒精饮料&#xff1b;烈酒&#xff1b;<俚>喝酒 sweat&#xff1a;英 [swet] 汗水&#xff1b;辛勤劳动 注意发音 plexiglass&#xff1a;美 [pleksɪˌglɑs] 树脂玻…

“消费新纪元:探索‘消费增值’的无限可能“

亲爱的顾客们&#xff0c;你们好&#xff01;今天&#xff0c;我想深入谈谈一种正在革新我们消费体验的模式——我们称之为“消费增值”。这个模式不仅仅保留了购物的乐趣&#xff0c;更在每一笔交易中融入了额外的价值&#xff0c;让消费过程焕发新生。 长久以来&#xff0c;我…