布隆过滤器详讲

本文旨在讲解布隆过滤器的原理以及实现方式,希望通过本文能使读者对布隆过滤器有一定的认识!

一、布隆过滤器的引入

在讲解布隆过滤器之前,我们还是先提及一下前面讲的位图行,位图可以处理大量的数据,广泛用于查找等操作!但是对于位图而言,起能处理的类型只能是整形,那么对于字符串等其他类型位图是无法处理的,那么这时就引进了我们下面要讲的布隆过滤器!

下面来介绍什么是布隆器,正如前面说的,位图不能处理字符串等类型,那么我们该怎么办呢,因为我们前面学习过哈希,所以我们可以使用哈希的思想将字符串类型先转化为整形,利用哈希将字符串转化为整形的方法有很多,下面来看一下常见的几种字符串哈希算法。

字符串哈希算法:

1.BKDRhash

该算法就是该字符串的每个字符的ascii码值乘上一个数,然后再进行相加! 

 2. SDBMhash


3.DJBhash


4.APhash

通过观察上述字符串哈希,我们可以发现,基本上都是字符串中的每一位乘上一个数然后进行获取最终结果的 。


布隆过滤器的介绍以及应用场景!

既然介绍了这些字符串哈希函数,那么我们就来讲一下布隆过滤器是如何诞生以及实现的,上面已经提到了,因为位图不能处理非整形的数据,那么面对一个非整形的数据,我们就需要进行一次哈希函数将其转化为整形,然后再进行映射到地址中去,但是对于字符串哈希函数,我们很难保证没有不同的字符串对应有相同的数字,此时再进行某一位的映射时,就会导致误差!例如:

对于上图,如果middle与end的对应的整形相同,那么就会映射在同一块区域,那么当end不存在的时候,但是middle存在的时候,就会导致误判,误判end也存在!这时有人就想出来将一个字符串对应多个哈希函数,这样误判会不会结束呢?答案是否定的!误判是肯定不会不存在的!但是会减少!字符串与对应值有着多对一的关系。我们也可以发现,这种误判只会出现在‘存在的情况!’对于“不存在”的情况,是一定准确的!所以就有人说了,那么发明这种东西有什么用呢?这时我们的大佬布隆在发明他的时候已经想到了应用场景,即其可以筛选一定的情况,从而加快查找的速率!

布隆过滤器的应用:

我们平时都玩过游戏,有很多游戏都需要用户自己定义自己的名字,但是还不能有重名的情况!对于游戏中所有的用户名,全部都存储在服务器中的数据库中,但是如果我们每次起一个名字,都要去访问服务器中的数据库,那岂不是太浪费时间了!

上图就是我们起一个名字的时候,当我们点击提交昵称的时候,会自动取服务器中的数据库中进行查询,如果查询到了有重复,就会给用户提示改昵称已经存在了,请在换个名字,这时,每当用户起一个名字那岂不是都得取服务器中的数据库进行查找一番么?

对与此问题,我们布隆大佬就想到,为何不在二者之间加上一个布隆过滤器呢,可以大大减少我们的查找时间呀!

 当添加过了布隆过滤器的时候,我们可以不用访问服务器中的数据库,直接通过布隆过滤器的返回结果进行判断,就像我们输入昵称的时候,还没有点击提交的时候,昵称旁边就是出现对号或错号的提示!这其实就是利用了布隆过滤器!但是布隆过滤器也存在问题,就是其结果只能准确的判断一个字符不存在,对与存在的情况,会出现误判,但是这时如果有的玩家好奇心强,我起了十个名字,8个不能用,我非得查一查这些名字都是谁在用,不查不知道,一查吓一跳,有的昵称竟然不存在也不让我起!必须反手一波举报,于是针对布隆过滤器的特性,我们增加一下条件即可!对于布隆过滤器中返回存在的昵称,因为其不一定准确,所以我们将这些昵称读取到服务器中即可!再次进行一次准确的检查再反馈给用户即可!

这样布隆过滤器的作用就起了很大的作用!大大增加了我们工作的效率!其实生活中也有很多存在使用布隆过滤器的场景,例如大量的数据中查询某一个人的信息,如果我们暴力查找,挨个去服务器中的数据库一一进行查找,那么效率会非常低下,此时我们就会先将标记某一个人的唯一信息,例如身份证号,手机号 转化为整形,再对相同的整形中进行服务器内部查询,即可快速完成查询信息!


二、布隆过滤器的实现!

既然布隆过滤器的作用以及讲解完毕,接下来我们看一下布隆过滤器是如何实现的吧!

对于布隆过滤器而言,其本质上还是一个位图,只不过该位图对应的哈希值有多个而已!所以我们只需要实现set函数,将其对应的多个位都set为1即可!!进行test的时候我们只需要将其对应的位都进行检测一波,如果有false就返回false即可,全为true再返回true,此时我们的true也不一定是准确的!因为会存在不同字符串的映射值可能相同的情况!但是我们的fasle是一定准确的!

下面就来看一下我们实现的布隆过滤器吧!

#pragma once
//布隆过滤器的实现!
//其本质上还是一个位图!
#include<string>
#include<bitset>struct BKDRHash
{size_t operator()(const string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};struct APHash
{size_t operator()(const string& key){size_t hash = 0;for (size_t i = 0; i < key.size(); i++){char ch = key[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const string& key){size_t hash = 5381;for (auto ch : key){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://set功能!  因为布隆过滤器其对应有多个映射值,所以我们使用多个哈希进行位映射!将对应的位置为1即可!!void set(const K& x){size_t hash1 = HashFunc1()(x)%N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!size_t hash2 = HashFunc2()(x)%N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!size_t hash3 = HashFunc3()(x)%N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!//对三个映射的位统统进行置一处理!!bt.set(hash1);bt.set(hash2);bt.set(hash3);}//test功能!  检测该字符是否存在,只需要将其对应的位进行test即可,如果有一个不存在直接返回false,//当三个都存在返回true即可,但是此时的true也是一种不准确的值!bool test(const K& key){size_t hash1 = HashFunc1()(key) % N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!size_t hash2 = HashFunc2()(key) % N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!size_t hash3 = HashFunc3()(key) % N;   //对N进行取余,保证其在这些空间上,防止因转化为整形过大!if (bt.test(hash1) == false){return false;}else if (bt.test(hash2) == false){return false;}else if (bt.test(hash3) == false){return false;}//当三者都为true时,才true!但是此时的true也是一个不准确的值!else if (bt.test(hash1) == true && bt.test(hash2) == true && bt.test(hash3) == true){return true;}}private:std::bitset<N>bt;   //本质上还是一个位图!
};

我们首先做的就是实现三个字符串哈希函数,用于我们的字符串映射的多个值问题!

细心的小伙伴们可能发现了,我没有实现reset函数,我为什么没有实现呢?对与布隆过滤器,其大多是不支持删除的!因为一个字符可能对应多个哈希值,某一位可能与已经存在的一位相同,如果将该位删除,那么与其相同的位也会删除掉,这就会导致误删的现象,但是我们可以使用引用计数的方法来解决reset的问题!

既然我们的布隆过滤器已经实现了,那么我们就简单的进行测试一下其效果吧!

我们将“数据结构”set到过滤器中,然后找一个与其比较相似的字符串“数据结构  ”进行测试,显然其不存在于我们的过滤器中,看来我们的布隆过滤器效果还是蛮不错的嘛! 

1.相似字符串的误判率

下面我们来看一下大量的相似字符串的误判率!

 2.不相似字符串的误判率

我们把数据个数N调到1000来观察一下结果!

根据结果还是容易看出来:相似字符串的误判率还是比较大的,那么这个误判率与什么有关系呢?

我把文章链接贴在下面:感兴趣的小伙伴可以看一下布隆过滤器的误判率的影响!详解布隆过滤器的原理,使用场景和注意事项 - 知乎 (zhihu.com) 


至此布隆过滤器的知识讲述完毕,下面来看一下另一个知识,哈希切分!

三、哈希切分 

 我们看一道例题来引出我们哈希切分!

例1:给定两个100亿的query,我们只有1G内存,如何快速找到两者的交集!

那么我们传统的哈希/红黑树是肯定不行的。

这时我们就可以利用hash函数将两个大文件分割成500个小文件,这时平均每个小文件占1G内存,然后对相互对应的小文件,利用set进行求交集即可! 这时就会有小伙伴问为什么要找对应的小文件呢,因为我们使用的是哈希函数,字符串相同的肯定会映射在同一个位置,那么这时该问题,不就解决了么!

但是还会存在一个小问题,就是当小文件中的内存还是比较大的话,该怎么办呢?

小文件大分两种情况:

1.都是一样的字符串,这时直接利用set进行去重既可以解决问题!

2.不是相同的字符串,这时我们只需要进行换一种哈希函数重新进行分配即可!

例2:给定一个超过100G的log file,log中存储着ip地址,求log file中最多的ip地址!

本题也是相同的道理,因为是100G的文件,所以我们仍然可以采用哈希切分的思想进行切分为小文件,然后一一处理即可!这时我们大可不必再切500个小文件,我们可以切割成100个小文件,平均一个小文件占1G内存。

我们通过对ip地址的哈希进行哈希切分,切分成100个小文件,我们的哈希函数可以是这样的!

hashi=Hash(ip)%100;

这样相同的ip地址肯定会分到相同的小文件中,这时我们对每一个小文件进行map统计次数即可!


至此,我们的布隆过滤器和哈希切分讲解完毕,希望读完本篇文章,读者能有一定的收获,也希望大大多多评论留言,互相讨论一波!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是 MySQL 回表?

什么是 MySQL 回表&#xff1f; 题目 什么是 MySQL 回表&#xff1f; 推荐解析 回表简介 1&#xff09;索引结构&#xff1a;MySQL 使用 B 树索引结构来加速数据的查找。B 树是一种多叉树&#xff0c;它的叶子节点中存储了完整的数据行&#xff0c;而非叶子节点存储了索引…

深度学习pytorch——过拟合欠拟合测试深度学习模型(持续更新)

随着项数越来越多&#xff0c;函数的图形就更加复杂&#xff0c;多项式也更加的复杂。 课时55 过拟合与欠拟合_哔哩哔哩_bilibili 如果利用多项式建造复杂模型&#xff0c;从仅仅一个常数至一个多次方函数&#xff0c;将会发现在线上的点会变得越来越多&#xff0c;这种逐渐接…

【2024系统架构设计】案例分析- 3 数据库

目录 一 基础知识 二 真题 一 基础知识 1 ORM ORM(Object—Relationl Mapping

机器学习——聚类算法-KMeans聚类

机器学习——聚类算法-KMeans聚类 在机器学习中&#xff0c;聚类是一种无监督学习方法&#xff0c;用于将数据集中的样本划分为若干个簇&#xff0c;使得同一簇内的样本相似度高&#xff0c;不同簇之间的样本相似度低。KMeans聚类是一种常用的聚类算法之一&#xff0c;本文将介…

Rust 02.控制、引用、切片Slice

1.控制流 //rust通过所有权机制来管理内存&#xff0c;编译器在编译就会根据所有权规则对内存的使用进行 //堆和栈 //编译的时候数据的类型大小是固定的&#xff0c;就是分配在栈上的 //编译的时候数据类型大小不固定&#xff0c;就是分配堆上的 fn main() {let x: i32 1;{le…

aws使用记录

数据传输&#xff08;S3) 安装命令行 安装awscli: https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions 直到 aws configure list 可以运行 身份验证&#xff1a; 运行&#xff1a; aws config…

EdgeGallery开发指南

API接口 简介 EdgeGallery支持第三方业务系统通过北向接口网关调用EdgeGallery的业务接口。调用流程如下图所示&#xff08;融合前端edgegallery-fe包含融合前端界面以及北向接口网关功能&#xff0c;通过浏览器访问时打开的是融合前端的界面&#xff0c;通过IP:Port/urlPref…

【力扣hot100】23 合并K个排序链表(c++)解析

23 合并K个排序链表&#xff08;c&#xff09;解析 题解 23 合并K个排序链表&#xff08;c&#xff09;解析1.1 暴力求解1.2 逐一比较1.3 优先队列1.4 逐一合并1.5 分治 在解决「合并K个排序链表」这个问题之前&#xff0c;我们先来看一个更简单的问题: 如何合并两个有序链表?…

libVLC 动态视频壁纸

在 Windows 上&#xff0c;你可能需要使用 Windows API 来设置壁纸&#xff0c;而在 Linux 上&#xff0c;你可能需要使用某种桌面环境特有的方法。在 macOS 上&#xff0c;这一功能可能受到限制。 效果图如下所示&#xff1a; 以下是一个简单的示例&#xff0c;说明了如何在 …

【前端学习——js篇】11.元素可见区域

具体见&#xff1a;https://github.com/febobo/web-interview 11.元素可见区域 ①offsetTop、scrollTop offsetTop&#xff0c;元素的上外边框至包含元素的上内边框之间的像素距离&#xff0c;其他offset属性如下图所示&#xff1a; 下面再来了解下clientWidth、clientHeight…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《考虑长周期供需不平衡风险的新型电力系统规划方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

codesys通过moudbus TCP连接西门子1214c,西门子做客户端

思路在codesys中发送数据到西门子&#xff0c;西门子原封不动的将数据传回。 1.首先配置codesys; 我设置了500个&#xff0c;但是好像发不这么多&#xff0c;只能120多个。因为什么来我忘了。但是这里不影响。 2.配置映射&#xff1a; 3.写代码 PROGRAM PLC_PRG VARarySendDa…

生产调度问题分类——机器视角

获取更多资讯&#xff0c;赶快关注上面的公众号吧&#xff01; 文章目录 单机调度并行机调度流水车间调度作业车间调度柔性作业车间开放车间总结 生产调度问题是实际工作中广泛存在的运筹学问题&#xff0c;可以描述为“给定若干加工任务&#xff0c;根据已有的生产条件&#…

JavaWeb学习笔记01

一、教程简介 全新JAVAWEB&#xff08;里程碑版&#xff09; 一套更适合后端工程师学习的WEB教程 All in Java 1、后端 ① Spring全家桶及微服务框架 ② 高性能数据库和消息组件 ③ Web攻击防护安全控制手段 ④ 其他第三方SDK生态环境 ...... 2、前端 ① 视图三大件&…

C是用什么语言写出来的?

C是用什么语言写出来的? C语言的起源和发展是一个迭代过程&#xff1a; 1. 最初的C语言编译器的开发始于对B语言的改进。B语言是由Ken Thompson设计的&#xff0c;它是基于BCPL语言简化而来的。在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 C语言的…

Sublime 彻底解决中文乱码

1. 按ctrl&#xff0c;打开Console&#xff0c;输入如下代码&#xff1a; import urllib.request,os; pf Package Control.sublime-package; ipp sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHand…

16:00面试,16:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

07_Response

文章目录 案例&#xff08;请求分发案例&#xff09; Response响应行响应头响应体特殊响应头refreshContent-typeContent-dispositionlocation 案例&#xff08;登录案例&#xff09; 案例&#xff08;请求分发案例&#xff09; 场景&#xff1a;有多个请求 Http://localhost:…

逐步学习Go-并发通道chan(channel)

概述 Go的Routines并发模型是基于CSP&#xff0c;如果你看过七周七并发&#xff0c;那么你应该了解。 什么是CSP&#xff1f; "Communicating Sequential Processes"&#xff08;CSP&#xff09;这个词组的含义来自其英文直译以及在计算机科学中的使用环境。 CSP…

day 36 贪心算法 part05● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

一遍过。首先把区间按左端点排序&#xff0c;然后右端点有两种情况。 假设是a区间&#xff0c;b区间。。。这样排列的顺序&#xff0c;那么 假设a[1]>b[0],如果a[1]>b[1]&#xff0c;就应该以b[1]为准&#xff0c;否则以a[1]为准。 class Solution { public:static bo…