哈希的应用(2)——布隆过滤器
文章目录
- 布隆过滤器
- 布隆过滤器的概念
- 布隆过滤器的实现
- 哈希函数个数和布隆过滤器长度
- 模拟实现
- 布隆过滤器的删除
- 小结
- 海量数据处理相关题
- 5.1哈希切割
- 5.2位图应用
- 5.3布隆过滤器
- 扩展
布隆过滤器
布隆过滤器的概念
比如说一个论坛要实现注册功能,每个人都有昵称(主码)。现在新用户输入昵称或者修改昵称,提交的时候要如何快速检测一下昵称是否被用过?有人使用,则提示一下,没人使用,则提交成功。
此时就是一个key的模型。比如说此时已经有100亿个用户昵称了。
目前有两种方式:
- 用哈希表存储用户记录,缺点:浪费空间。
- 用位图存储用户记录。优点:节省空间、快。缺点:只能处理整数。不能解决哈希冲突。
因此针对字符串等更加复杂的类型,能否设计出一个位图一样的key在不在模型且节省空间的数据结构呢?
字符串可以通过BKDR算法变成整数,但是存在哈希冲突。但是位图只有一个位,也没法存指针形成单链表。
布隆解决方式:这个问题不能解决,那能不能降低误判概率?每个值映射一个位容易冲突,那把一个值映射成多个位。
映射多个位,还是可能存在误判,但是误判的概率低了,因为要映射的多个位都被占用冲突,才会误判。(类似字符串的双哈希、多哈希)
布隆过滤器,出发点是节省空间,效率高,一个值映射的位越多,消耗的空间越大。
将哈希与位图结合,即布隆过滤器,布隆过滤器是位图变形和延伸。
重点:
判断昵称用过:存在误判。当前昵称映射的位置可能被其他给占用了。
判断昵称没用过:准确的。
布隆过滤器的实现
哈希函数个数和布隆过滤器长度
k为哈希函数个数,m为布隆过滤器长度,n为插入的元素的个数,p为误报率。
k = m n l n ( 2 ) k=\frac{m}{n}ln(2) k=nmln(2)
当冲突概率高的时候可以类似控制平衡因子那样对布隆过滤器进行增容。
模拟实现
#pragma once
#include"BitSet.h"struct HashBKDR
{size_t operator()(const string& s){size_t value = 0;for (auto ch : s){value = value * 131 + ch;}return value;}
}; struct HashAP
{size_t operator()(const std::string& s){register size_t hash = 0;size_t ch;for (long i = 0; i < s.size(); i++){ch = s[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct HashDJB
{size_t operator()(const std::string& s){register size_t hash = 5381;for (auto ch : s){hash += (hash << 5) + ch;}return hash;}
};template<size_t N,class K = string ,class Hash1=HashBKDR,class Hash2 = HashAP,class Hash3 = HashDJB>
class BloomFilter
{public:void Set(const K& key){size_t i1 = Hash1()(key) % N;//匿名对象size_t i2 = Hash2()(key) % N;size_t i3 = Hash3()(key) % N;cout << i1 << " " << i2 << " " << i3 << endl;_bitset.Set(i1);_bitset.Set(i2);_bitset.Set(i3);}bool Test(const K& key){size_t i1 = Hash1()(key) % N;//匿名对象if (_bitset.Test(i1) == false){return false;}size_t i2 = Hash2()(key) % N;if (_bitset.Test(i2) == false){return false;}size_t i3 = Hash3()(key) % N;if (_bitset.Test(i3) == false){return false;}return true;//这里三个位都在,有可能是其他key占的,是不准确的。}
private:Y::BitSet<N> _bitset;
};void TestBloomFilter()
{BloomFilter<100> bf;bf.Set("张三");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("苹果") << endl;
}
布隆过滤器的删除
一般情况下布隆过滤器是不能删除的。
但是有些场景可能只能妥协。
布隆过滤器删除的办法是引用计数。
使用多个位标识一个位置,多个值映射时,++计数;删除时,–计数。比如说4位,那么有16个值同时映射这个位置就不行了。整体还是比哈希好。
真的要实现的时候可以简单点,就实现8bit的,vector<char> _bitset
,找位置如果存在就对该位置++,删除就–。
小结
布隆过滤器优点:节省空间(相比于平衡搜索树和哈希表),效率高。
布隆过滤器缺点:存在误判,判断在是不准确的,判断不在是准确的。布隆过滤器一般不支持删除。
布隆过滤器使用的前提:能够容许他的误判。
实际场景中比如危险网站的检测,可以用布隆过滤器判断是否在危险网站集合中。
数据库是存在硬盘上的,假如系统所有用户的电话号码都存储在数据库的用户表。场景:注册新账号的时候在你没提交的时候提示一下这个手机号是否注册过。然而IO是比较慢的,这种场景可以在前端放一个布隆过滤器,里面放数据库的手机号,先布隆里面判在不在,布隆的判断不存在是准确的,直接就可以了。如果手机号在布隆过滤器中,这时候就要去数据库中找。
海量数据处理相关题
5.1哈希切割
给一个超过100G大小的log file,log中存着IP地址,设计算法找到出现次数最多的IP地址?
与上题条件相同,如何找到top K的IP?
如何直接用Linux系统命令实现?
对于大文件的思路是类似的,大文件不好处理就用哈希切分成小文件。
哈希切分的特点:相同的记录会进入下标相同的文件中。所以我们直接统计小文件中的次数即可。
假设生成A0~A99的100个文件,依次读取大文件中ip,计算每个ip映射的文件号,i=HashBKDR()(ip)%100,这个ip就进入 A i A_i Ai号小文件。
再依次读取A0~A99,读取Ai文件,如果Ai大于2G,可以类似上面切分一下。如果小于2G,可以直接统计每个小文件map<string,int>统计次数获得最多的。最后多个文件比较出最大的那个。
出现次数最多k个ip,用大堆还是小堆?建k个数的小堆。后面来的比top()大就进堆。
linux系统命令可以直接对文件sort然后count。
5.2位图应用
位图应用的题也可以哈希切分。
- 给定100亿个整数,设计算法找到只出现一次的整数?
- 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
- 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
5.3布隆过滤器
- 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
- 该query可能是http请求,也可能是sql查询。其实就是一个字符串。
- 近似算法:将其中一个文件全部映射到布隆过滤器,另一个文件在过滤器中查询,找得到的就是交集。
- 精确算法:一个文件大小是多少?100亿个query,假设平均每个query是20byte,那么100亿个query就是100亿*20字节,而之前算的1G大约是10亿字节,那么一个文件大约是200G。读取A文件中的100亿个query字符串,进行哈希切分。
- 我们有1G内存,哈希切分的每个小文件不一定平均,建议切成400份,创建A0~A399的400个小文件,读取文件中的每一个query,计算i=HashBKDR(query)%400。这个query就写入 A i A_i Ai的小文件中。
- 另一边创建B0~B399的400个小文件,读取文件中的每一个query,计算i=HashBKDR(query)%400。这个query就写入 B i B_i Bi的小文件中。
- 如果两边存在相同的query,则两者模后是在同一个下标的文件中的。因此可以在每个小文件中比较。哈希切分的特点:A和B文件中相同的query分别进入了下标相同的 A i A_i Ai和 B i B_i Bi文件中。
- 如果存在文件大小大于1G。若A0超过B0没超过,则放少的那个。如果两个都超过,可以尝试把整体400份再扩大,不行的话就算下大小把大的两个再切分一次。
- 如何扩展BloomFilter使得它支持删除元素的操作
- 见删除一节。
扩展
以后简单扩展:一致性哈希,哈希与加密
关于一致性哈希:
在实际开发应用中,实际场景大致是这样的:
- 数据量大,单台机器存不下。
- 只存一台机器,安全性不足,多副本。副本之间物理上也是有很大的间距的,防止不可抗力。
这样就要考虑一个问题,找数据的时候服务器怎么知道要找的数据在哪一台机器。每个服务器相当于一个桶,进行编号,那么对于访问的ip进行取模来知道在哪个机器。这样就会同步产生一个问题,当扩容机器或者减少机器的时候,模的关系就发生变化了,怎么处理数据的问题。这就是一致性哈希处理的问题。
关于哈希与加密:密码学方向。
哈希的应用(2)——布隆过滤器相关推荐
- 哈希(解决哈希冲突,封装map/set,哈希的应用{位图/布隆过滤器})
文章目录 如何解决哈希冲突: ①闭散列:也叫开放定址法,如果发送哈希冲突了,就去找下一个空位置 ②开散列 -- 拉链法/哈希桶 封装map和set 哈希表的代码 封装的unordered_set 封装 ...
- 哈希的应用->布隆过滤器
为什么用布隆过滤器 这个是基于位图的一个超级牛皮的一个数据结构.举个例子,假设我们创建Steam账号,我们的账户名字是不允许重复的,所以我们需要找到一个没有人使用过的名字,但是我们得知道现在这个名字是 ...
- 哈希切割+布隆过滤器
目录 布隆过滤器 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 插入 set函数 布隆过滤器长度的设置 测试布隆误判率 布隆过滤器删除 布隆过滤器的实现场景 布隆过滤器的扩展以及哈希切分 布隆 ...
- 哈希表应用——布隆过滤器
注:布隆过滤是用来处理海量数据且允许存在误判 目录 布隆过滤器提出 布隆过滤器概念 布隆过滤器的理论知识 布隆过滤器的实现 布隆过滤器的删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤器的应用场景 哈希 ...
- 哈希的应用 —— 布隆过滤器
文章目录 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 布隆过滤器的插入 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器的优点 布隆过滤器的缺陷 布隆过滤器使用场景 布隆过滤器的提出 在注册账 ...
- 算法:详解布隆过滤器的原理、使用场景和注意事项@知乎.Young Chen
算法:详解布隆过滤器的原理.使用场景和注意事项@知乎.Young Chen 什么是布隆过滤器 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data struc ...
- 详解布隆过滤器的原理、使用场景和注意事项
在进入正文之前,之前看到的有句话我觉得说得很好: Data structures are nothing different. They are like the bookshelves of you ...
- 海量数据处理(一) :位图与布隆过滤器的概念以及实现
目录 位图 位图概念 位图的应用 位图的实现思路 set reset test 完整代码 布隆过滤器 布隆过滤器概念 布隆过滤器的优缺点 优点 缺点 布隆过滤器的实现思路 哈希冲突的问题 如何选择哈希 ...
- 布隆过滤器速度_详解布隆过滤器的原理、使用场景和注意事项
今天碰到个业务,他的 Redis 集群有个大 Value 用途是作为布隆过滤器,但沟通的时候被小怼了一下,意思大概是 "布隆过滤器原理都不懂,还要我优化?".技术菜被人怼认了.怪不 ...
最新文章
- HDU 1757 A Simple Math Problem
- 『并发包入坑指北』之阻塞队列
- P1892 [BOI2003]团伙(并查集,反集)难度⭐⭐★
- redis的rpm包下载安装
- 方差、标准差、均方根误差
- kafka消费者开发方式小结
- TinaFace:人脸检测新纪录!
- android room 线程,Android协程——RoomCoroutines-Go语言中文社区
- javascript--Math相关
- VLfeat库---研习
- 《神经网络与深度学习从理论到实践-邱锡鹏》笔记(持续更行ing)
- 人人都是产品经理2.0
- python使用 Captcha 模块来生成验证码图片
- matlab迭代求解泊松方程,MATLAB编程求解二维泊松方程
- android 跑马灯出现重复跳动、不滚动问题
- android 高通与MTK编译命令
- click和touchmove vue_移动端touch事件影响click事件以及在touchmove添加preventDefault导致页面无法滚动的解决方法...
- r720服务器怎么查看硬盘性能,r720服务器如何看配置
- 基于java基于javaweb的管理系统设计与实现怎样选题思路分享
- css–sprit_高级CSS –类已用完–通过使用结构化格式标签避免类