海量数据去重的Hash与BloomFilter

今天我们谈论一下散列表,我之前的两个博文写的都是关于平衡二叉树的

平衡二叉树

增删改查时间复杂度为log2n
平衡的目的是增删改以后,保证下次搜索能稳定排除一半的数据;
总结:通过比较保证有序,通过每次排除一半的元素达到快速索引的目的;

散列表

根据KEY计算KEy在表中的位置的数据结构;是key和其所在存储地址的映射关系;

hash冲突

映射函数hash(key)=addr;HASH函数可能会把两个或两个以上的不同的KEY映射到同一个地址,这种情况称之为冲突(或者hash碰撞)

选择hash
  • 计算速度快
  • 强随机分布(等概率、均匀地分布在整个地址空间)
  • murmurhash1,murmurhash2,murmurhash3,siphash
    ( redis6.0 当中使用,rust 等大多数语言选用的 hash 算法来实
    现 hashmap),cityhash 都具备强随机分布性;测试地址如
    下:
    https://github.com/aappleby/smhasher
  • siphash 主要解决字符串接近的强随机分布性;
负载因子
  • 数组存储的元素的个数/数据长度;用来形容散列表的存储密度;负载因子越小,冲突越小,负载因子越大,冲突越大;
冲突处理
链表法

引用链表来处理哈希冲突;也就是将冲突元素用链表链接起来;这也是常用的处理冲突的方式;但是可能出现一种极端情况,冲突元素比较多,该冲突链表过长,这个时候可以将这个链表转换为红黑树时间复杂O(log2n);那么判断该链表过长的依据是多少?可以采用256(经验值)个节点的时候将链表结构转换为红黑树或堆结构。

开放寻址法

将所有的元素都存放在哈希表的数组中,不使用额外的数据结构;一般使用线性探查的思路解决;1. 当插入新元素的时候,使用哈希函数在哈希表中定位元素位置;2. 检查数组中该槽位索引是否存在元素。如果该槽位为空,则插入,否则3;3. 在2检测的槽位索引上加一定步长为一下几种: (1) i+1,i+2,i+3,i+4,...,i+n (2)i-12,1-22,i-33,1+42,...这两种都会导致同类hash聚集;也就是近似值它的hash值也近似,那么它的数组槽位也靠近,形成hash聚集;第一种同类聚集冲突在前,第二种只是将聚集冲突延后;另外还可以使用双重哈希来解决上面出现的hash聚集现象:

在.net HashTable类的hash函数Hk定义如下:
Hk(key) = [GetHash(key) + k * (1 +
(((GetHash(key) >> 5) + 1) %
(hashsize – 1)))] % hashsize
在此 (1 + (((GetHash(key) >> 5) + 1) %
(hashsize – 1))) 与 hashsize
互为素数(两数互为素数表示两者没有共同的质因⼦);
执⾏了 hashsize 次探查后,哈希表中的每⼀个位置都有
且只有⼀次被访问到,也就是
说,对于给定的 key,对哈希表中的同⼀位置不会同时使⽤
Hi 和 Hj; 

布隆过滤器

背景

布隆过滤器是一种概率性数据结构,它的特点是高效地插入和查询,能确定某个字符串一点不存在或者可能存在
布隆过滤器不存储具体数据,所以占用空间小,查询结构存在误差,但是误差可控,同时不支持删除操作。

构成

位图(BIT数组)+n个hash函数
m%2n=m&(2n-1)

原理

当一个元素位图时,通过K个HASH函数将这个元素映射到位图的K个点,并把它们置为1;当检索时,再通过K个hash函数运算检测位图的K个点是否都是为1;如果有不为1的点,那么认为该key不存在;如果全部为1,则可能存在;
为什么不支持删除操作?

  • 在位图中每个槽位值有两种状态(0或者1),一个槽位被设置为1状态,但不确定它被设置了多少次;也就是不知道被多个key哈希映射而来以及是被具体哪个hash函数映射而来;
应用场景

布隆过滤器通常用于判断某个KEY一定不存在的场景,允许判断存在时有误差的情况;
常见处理场景:(1)缓存穿透的解决;(2)热key限流;

  • 描述缓存场景,为了减轻数据库(mysql)的访问压力,在server端与数据库(mysql)之间加入缓存用来存储热点数据
  • 描述缓存穿透,server端请求数据时,缓存和数据库都不包含该数据,最终请求压力全部涌向数据库;
  • 数据请求步骤,如图所示
  • 发生原因:黑客利用漏洞伪造数据攻击或内部业务BUG造成大量重复请求不存在的数据;
  • 解决方案:如果图中所示;
应用分析

在实际应用中,该选择多少个hash函数?要分配多少空间的位图?预期存储多少元素?如何控制误差?
公式如下:
n -- 预期布隆过滤器中元素的个数,如上图 只有str1和str2 两
个元素 那么 n=2
p -- 假阳率,在0-1之间 0.000000
m -- 位图所占空间
k -- hash函数的个数
公式如下:
n = ceil(m / (-k / log(1 - exp(log(p) / k))))
p = pow(1 - exp(-k / (m / n)), k)
m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
k = round((m / n) * log(2));

变量关系

假定4个初始值:
n=4000
p=0.000000001
m=172532
k=30

面试百度hash函数实现过程当中 为什么会出现i*31?

  • i * 31 = i * (32-1) = i * (1<<5 -1) = i << 5 - i;
    *31 质数,hash 随机分布性是最好的;

确定n和p

在时间使用布隆过滤器时候,首先确定n和p,通过上面的运算得出m和k;
通常可以在下面这个网站上选出合适的值;
https://hur.st/bloomfilter

推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
服务器
音视频
dpdk
Linux内核

posted @ 2022-08-14 17:42  飘雨的河  阅读(104)  评论(0编辑  收藏  举报