1.3 海量数据去重的Hash与BloomFilter,bitmap

  • 知识树
  • 1、海量数据查找的应用场景
  • 2、平衡二叉树
  • 3、哪些算法涉及二分查找
  • 4、散列表
    • (1)hash冲突
    • (2)负载因子
    • (3)解决hash冲突的方法
      • ① 链表法(redis中、C++或JAVA中的unordered_map)
      • ② 开放寻址法
        • 1)线性探查
        • 2)通常使用【双重哈希】来解决【hash聚集】
  • 5、布隆过滤器
    • (1)布隆过滤器相较于散列表和平衡二叉树的优点
    • (2)布隆过滤器的构成
    • (3)布隆过滤器查找key是否存在的过程
    • (4)布隆过滤器的原理
    • (5)实际应用中怎么使用布隆过滤器
    • (6)布隆过滤器的应用场景
    • (7)面试问题:布隆过滤器如何解决缓存穿透
    • (8)四个变量的关系
  • 6、怎么选择hash函数
  • 7、工作中怎么使用布隆过滤器
  • 7、分布式一致性hash
    • (1)分布式一致性hash介绍
    • (2)解决hash偏移
    • (2)解决【分布式一致性hash只造成部分的影响】的问题
  • 8、感谢大家的观看,我是COSMIC

本博客总结自零声教育的课程

本博客将和大家一起学习海量数据去重的hash的相关知识,包括海量数据查找的应用场景、平衡二叉树、hash冲突、hash聚集、如何解决hash冲突、布隆过滤器、怎么选择hash函数、分布式一致性hash存在的问题及解决方法等

知识树

1、海量数据查找的应用场景

(1)使用word文档时,word如何判断某个单词是否拼写正确?
(2)网络爬虫程序,怎么让它不去爬相同的url页面?(将url当作key,记录key,查找key来判断是否已经爬取过该url)
(3)垃圾邮件过滤算法如何设计?
(4)公安办案时,如何判断某嫌疑人是否在网逃名单中?
(5)缓存穿透问题如何解决?
★★★需求:从海量数据中查询某个字符串是否存在

2、平衡二叉树

平衡二叉树全称为平衡二叉搜索树
1、增删改查的时间复杂度为O(log2n)(平衡性使得时间复杂度稳定)
2、平衡的目的是:增删改后,保证下次搜能稳定排除一半的数据
3、O(log2n)的直观理解:
①如果有100万个结点,最多比较20次:n为100万,log2 n = log10 n / log10 2 = 6 / 0.301 = 20(小于20),因此最多比较20次
②如果有10亿个结点,最多比较30次:log2 n = log10 n / log10 2 = 9 / 0.301 = 30(小于30),因此最多比较30次

PS:O(log2n)已经很快了,再快就是O(1)了
总结:★平衡二叉树通过【比较】保证有序,通过每次排除一半的元素达到快速索引的目的

3、哪些算法涉及二分查找


1、AVL树是高度平衡的,左右子树的高度之差<=1;而红黑树只是黑高(黑色结点的高度相同)
2、平衡多路搜索树:★B+树的每个结点要和磁盘页相对应,为了快速索引磁盘,所以结点不能只存储一个元素而要存储多个元素,要和磁盘的页相匹配;可以用二分查找,因为每个叶子结点中的存储是顺序存储的(叶子结点中的元素是顺序排列的),从而可以用二分查找快速查找(平衡多路搜索树的时间复杂度为O(h*log2n))

因为平衡二叉树要
①存储元素
②比较字符串
所以,面对海量数据时平衡二叉树的时间复杂度就比较高了,因此平衡二叉树面对海量数据时是不被接受的

4、散列表

散列表 = 哈希 + 数组
散列表可以根据hash函数直接将key映射到存储地址(key =>存储地址):
映射函数Hash(key) = addr
(散列表较平衡二叉树的优点:避免了字符串的比较)

(1)hash冲突

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

(2)负载因子

用来描述hash冲突的程度
1、负载因子 = 数组存储元素的个数 / 数据长度
2、负载因子用来形容散列表的存储密度;负载因子越小,冲突越小;负载因子越大,冲突越大
3、不同数据结构的负载因子不同,比如map中的负载因子是0.6几,redis中的负载因子为1

(3)解决hash冲突的方法

① 链表法(redis中、C++或JAVA中的unordered_map)


(1)引用链表来处理哈希冲突,也就是将冲突元素用链表链接起来(如上图)
(2)但是可能出现一种极端情况:冲突元素比较多,该冲突链表过长,这个时候会将我们的算法退化成O(n)
(3)解决:因此我们会将这个链表转换为红黑树或AVL树,为了将链表时间复杂度O(n)转换为红黑树时间复杂度O(log2n),以便快速查找(冲突不大时是O(1),冲突大时转化为红黑树或AVL树变为O(log2n));
(4)那么链表多长算过长呢?可以当超过256(经验值)个节点的时候将链表结构转换为红黑树结构
(5)插入新的冲突结点的时候,是插在链表的头部还是尾部:
①头插法 ②尾插法:
①头插法:用于数据库、redis、memcached等中,因为对于数据库而言,我们认为【最近插入的元素未来也会最先访问】

② 开放寻址法

将所有的元素都存放在哈希表的数组中,不使用额外的数据结构:数组中每个位置只存储一个元素:

1)线性探查

步骤:
①当插入新元素时,使用哈希函数在哈希表中定位元素位置;
②检查数组中该槽位索引是否存在元素;如果该槽位为空,则插入;若该槽位不为空则在该槽位索引上【加一定步长】重复检查是否存在元素,以此类推……(线性探查)

线性探查的步长选择分为以下几种:
①步长:i+1,i+2,i+3,。。。,i+n
问题:随着负载因子的不断增加,大部分槽位中已经包含了元素,因此可能会进行多次探查,可能会遍历整个数组(hash聚集)
②能延缓hash聚集现象的产生:
步长:i-12,i+22,i-32,i+42,。。。
总结:①和②都会导致同类hash聚集(这两种方法基本不会使用),即近似值的hash值也近似,那么它的数组槽位也靠近,形成 hash聚集;①会更快产生hash聚集,②能够延缓hash聚集现象的产生

hash聚集现象:hash冲突时,进行线性探查后还是发生hash冲突

2)通常使用【双重哈希】来解决【hash聚集】

构造一个特殊的hash函数HK(key):


选取一个hash函数,通过一系列运算,【运算结果与hashsize互为质数】的形式再生成一个hash函数,通过这个函数来解决hash聚集(详情见具体原理)

总结:散列表面对海量数据(几百万或几亿条数据)的时候,散列表比平衡二叉树的优点:不需要进行字符串的比较,★但是散列表和平衡二叉树都有一个缺点:都需要存储具体元素,散列表要存储key,hash冲突的时候还需要比较key是否是一样的值,因此散列表和平衡二叉树都不能用在统计上面

5、布隆过滤器

布隆过滤器:需要构造n个hash函数,多个hash函数怎么避免hash聚集现象:使用双重hash(见上面)

布隆过滤器是一种概率型数据结构,它的特点是高效地插入和查询,能确定某个字符串一定不存在或者可能存在
布隆过滤器不存储具体数据(通过n个hash函数在n个BIT位中标识为1,通过这样的方式来标识key的存在),所以占用空间小,查询结果存在误差,但是误差可控,同时不支持删除操作

(1)布隆过滤器相较于散列表和平衡二叉树的优点

①不存储具体的元素(平衡二叉树和散列表都要存储具体的元素),占用的内存小
②通过hash的方式算出具体的值,但是不比较具体的key(平衡二叉树需要比较key,散列表不用比较key)
以节约内存的方式快速地判断某个字符串是否存在
上述也是布隆过滤器的优点,可以根据上述的需求来选择布隆过滤器

(2)布隆过滤器的构成

布隆过滤器的构成:位图(BIT数组)+ n个hash函数
位图:可以想象成是一个数组,数组中的元素只有0或1

(3)布隆过滤器查找key是否存在的过程

★过程:
1、某个key通过一个hash函数能够找到数组中的一个位置(一个BIT位)
2、将key传入到多个hash函数中,生成多个BIT位,【由这多个BIT位来告诉我们key是否存在】
3、计算,计算出存入布隆过滤器的横纵坐标(i, j)
优化:将【★★★取余运算转化成二进制的位运算】:(很多开源框架都使用这种运算方式)
举例:m % n = m & (n - 1)

(4)布隆过滤器的原理

1、插入:当一个元素加入位图时,通过k 个hash 函数将这个元素映射到位图的k个点,并把它们置为1
2、查询:查询时,再通过k 个hash 函数运算检测位图的k个点是否都为1;如果有不为1的点,那么认为该key 不存在;如果全部为1,则可能存在(若为1则只能证明可能存在,因为可能是其他的key(string类型)将该位映射为1的)

★布隆过滤器的架构图:(3个hash函数,2个字符串,看如何进行映射的)

★为什么布隆过滤器不支持删除操作?
答:在位图中每个槽位只有两种状态(0或1),一个槽位被设置为1状态,但不确定它被设置了多少次,即【不知道被多少个key哈希映射而来】或【是被具体哪个hash 函数映射而来】
若想让布隆过滤器支持删除操作的话,可以准备2个布隆过滤器,一个正常使用,一个存储删除了的元素,先在第一个布隆过滤器中判断是否存在,再在第二个布隆过滤器中判断是否已经删除(这样判断删除,也是会存在误差的)

(5)实际应用中怎么使用布隆过滤器

在实际应用中,该选择多少个hash 函数?要分配多少空间的位图?预期存储多少元素(会存在负载因子的问题,hash冲突)?如何控制误差?
n:预期要在布隆过滤器中存储的元素个数,如上图只有str1和str2两个元素,则n=2
p:假阳率:【误判的概率】,在0和1之间
m:位图所占空间的大小
k:hash函数的个数

github上很多实现布隆过滤器的代码

(6)布隆过滤器的应用场景

★★★布隆过滤器的应用场景
布隆过滤器通常用于判断某个key一定不存在的场景,同时允许判断存在时有误差的情况
布隆过滤器常见的使用场景:①缓存穿透的解决 ②热key限流(KV存储,key-value存储) ③黑名单 ④查重 等等

热key限流:
如果访问某一个key到达一定的频次,则将该key存入布隆过滤器中,下次访问的时候先去布隆过滤器中查是否是热key,若在布隆过滤器中(有一定概率判断错误),即是热key,则返回访问失败;如果不在布隆过滤器中,即不是热key,则可以继续直接访问

(7)面试问题:布隆过滤器如何解决缓存穿透


答:
1、描述缓存场景:server端原来是和mysql建立连接,但是随着项目存储数据的增加,读写的速度越来越低,考虑增加一个redis缓存来减少mysql的读写压力;因此为了减轻数据库(mysql)的访问压力,在server端与数据库(mysql)之间加入缓存redis来存储热点数据
2、描述缓存穿透是怎么产生的:
缓存穿透:加入redis是为了减轻mysql的访问压力,但是如果server端请求数据时 缓存和数据库都不包含该数据,那么最终请求压力会全部涌向数据库(redis缓存没有用到,相当于直接穿透过去了,因此叫做缓存穿透),可能会造成系统瘫痪
3、数据请求步骤图示:
因为redis缓存中存储着热点数据,因此server先去访问redis的数据,如果redis中有该数据则直接返回;若redis中没有该数据则去访问mysql,若mysql有数据则直接返回,并将该数据存入redis中,若没有数据就没有数据返回

4、发生原因:黑客利用漏洞伪造数据攻击 或者 内部业务bug 造成大量重复请求不存在的数据,把数据库(mysql)打崩

★存在的问题:根据客户端的请求【没有进行数据(key)的验证】,而是直接访问mysql和后端缓存系统redis

★解决方案:在server端的布隆过滤器中预先存储我们可能访问的这些key,【访问key之前先在server端的布隆过滤器中进行判断key是否存在】,即先对key进行验证而不是直接就去访问mysql和后端缓存系统;若key一定不存在则直接返回,此时没有走redis或mysql,

(8)四个变量的关系

假定四个初始值:
n = 4000,存储的元素个数
p = 0.00000001,误判的概率
m = 172532,数组存储的空间
k = 30,预备多少个hash函数

1、p和n的关系:固定m和k来看p和n的关系:因为空间m是固定的,存入的数据n越来越多所以更容易误判,所以假阳率提升了:

2、p和m的关系:随着存储空间m的不断增大,假阳率越来越低

3、p和k的关系:hash函数的个数越多,假阳率越低;但是当k > 31时假阳率会增加

问题:面试百度:hash函数实现的过程当中为什么会经常出现一个值乘31(即为什么会经常出现i * 31)?
答:
1、将乘法运算转化为位运算:

2、31是质数,hash函数对质数取余(例如 % 17,% 31,% 101等)后【hash函数会更加均匀】(hash函数的【随机分布性更好】,取余31后【hash函数的随机分布性是表现得最好的】)

6、怎么选择hash函数

1、计算速度快:不要有乘法、除法、取余的操作,将这些操作都转化为二进制的位操作
2、强随机分布性(等概率、均匀地分布在整个地址空间):希望通过hash函数后,能够【等概率地、均匀地】插入到数组的槽位中,能够保证hash冲突的概率尽可能小

用的比较多的hash函数:murmurhash1,murmurhash2,murmurhash3,siphash (redis6.0当中使用,rust等大多数语言选用的hash算法来实现hashmap) , cityhash都具备强随机分布性;测试地址如下:

★murmurhash2、siphash、cityhash是常用的hash函数
★siphash主要解决key长的很接近(字符串长的很接近)时的强随机分布性,例如key为10001和key为10002(key长的很接近的话可能使得hash出来的值也比较接近,容易产生hash聚集)
★redis是个KV数据库(key-value数据库),其中key都是string类型的字符串

7、工作中怎么使用布隆过滤器

在实际使用布隆过滤器时,★★★首先要确定n和p,再通过公式得出m和k
★通常可以在下面这个网站上选出合适的m和k值:

填入n和p后会自动算出m和k:(不需要自己根据公式算)

★生成k个hash函数:
选择一个hash函数,通过给hash传递不同的种子偏移值,采用线性探寻的方式构造多个hash函数:Pos[i]为构造的一个hash函数

7、分布式一致性hash

1、分布式一致性 hash算法将【哈希空间组织成一个虚拟的圆环】,圆环的大小是2^32
2、算法为: hash(ip) % 2^32
最终会得到一个 [0, 2^32-1] 之间的一个无符号整型,这个整数代表【服务器的编号】,多个服务器都通过这种方式在hash 环上映射一个点来【标识该服务器的位置】;当用户操作某个key,通过同样的算法生成一个值,沿环顺时针定位某个服务器,那么该key就在该服务器中:

分布式一致性hash最早用来解决分布式缓存问题:
问题:为什么分布式缓存需要hash?
答:因为原来的memcached是不带横向扩展的集群操作的
横向扩展的集群操作:将一个memcached拆成多个memcached,我们希望将数据均衡地缓存在多个memcached中:

(左边是服务端,右边是多个mamcached(缓存服务器))
最早是用hash(key) % 节点数量,比如上图:hash(key) % 3得到0、1、2,有一个数组存储着缓存服务器的ip地址+端口,根据得到的0、1、2将数据分别对应三个缓存服务器的ip地址和端口,即分别存储到右边不同的三个缓存服务器中

存在的问题:数据访问压力不断增大后需要增加节点,比如右边添加了一个缓存服务器,即右边有4个缓存服务器了,hash运算相应变为了hash(key) % 4,这样会造成数据乱套

解决方案:【分布式一致性hash】

(1)分布式一致性hash介绍

★分布式一致性hash:将算法固定为hash(key) % 2^32 (一个值对232取余后,结果值一定落在0到232-1之间):
将 2^32 想象成一个hash圆环(或循环数组,索引从0到2^32-1):

1、对节点进行hash:将三个节点hash到hash圆环中:hash(ip:port) % 2^32

(三台缓存服务器A、B、C)

2、对key进行hash:hash(key) % 2^32:
hash后的结果在hash圆环的某个位置,顺时针去找下一个节点(如下图,为B节点),则该key就去操作缓存服务器B

添加节点(访问压力过大时添加缓存服务器):若现在增加一个D节点:A到B 和 B到C 之间的数据没有受到影响,影响的是C到D之间的数据,原本是存储在A上的,结果现在被D截断了,要存储在D上,因此问题①:分布式一致性hash只造成部分的影响

问题②hash偏移:由于hash函数的强随机性可能会出现【两个缓存服务器结点的位置特别集中】,会造成数据存储不均衡:(例如下图A和B非常集中)

★★★hash偏移产生的主要原因:服务器结点太少了,若服务器结点足够多则肯定是均匀分布的(强随机分布性的【均匀分布】的前提是【数量足够多】,涉及到概率的问题都是数量的问题)

(2)解决hash偏移

★★★hash偏移产生的主要原因:服务器结点太少了,若服务器结点足够多则肯定是均匀分布的(强随机分布性的【均匀分布】的前提是【数量足够多】,涉及到概率的问题都是数量的问题)

★★★解决hash偏移:加虚拟结点,【为每个服务器生成多个虚拟结点】,假设生成30个A节点的虚拟节点:
hash(ip:port:1) (1为序列号,一直到30)
hash(ip:port:2)
hash(ip:port:3)

hash(ip:port:30)

1、第一步:hash虚拟节点:hash(ip:port:1)
★要将【真实结点和虚拟结点构建一个关系】,使得能够【根据虚拟节点来找到真实ip】:方法:截取ip:port:1的ip:port作为key,就得到了真实ip
再来一个服务器B,和上面一样,构造30个B的虚拟节点:
同样:
hash(ip:port:1)
hash(ip:port:2)
hash(ip:port:3)

hash(ip:port:30)


2、第二步:hash(key),同样在hash圆环中,【顺时针查找】,若查找到的是红色节点,则存放到服务器B,若查找到的是黑色节点,则存放到服务器A
这样就解决了【问题②hash偏移】的问题

(2)解决【分布式一致性hash只造成部分的影响】的问题

使用【数据迁移】来解决【问题①分布式一致性hash只造成部分的影响】:

这里不详细展开了,给大家提供了参考链接,大家可以自行查看

8、感谢大家的观看,我是COSMIC

COSMIC的后端学习之路——1.3 海量数据去重的Hash与BloomFilter(布隆过滤器),bitmap(位图)相关推荐

  1. COSMIC的后端学习之路——1.1 随处可见的红黑树

    1.1 随处可见的红黑树 1.知识树 2.红黑树的性质(3) 3.红黑树的使用(2) 4.红黑树用在哪里(举例) 5.判断是否为叶子节点的方法(2) 6.红黑树的旋转 (1)左旋 (2)右旋 7.操作 ...

  2. COSMIC的后端学习之路——2.1 C++11新特性(1)

    2.1 C++11新特性(1) 知识树 1.智能指针 (1)std::shared_ptr:共享的智能指针 ①初始化 ②获取原始指针 ③指定删除器(自定义删除对象) ④一些错误用法 (2)std::u ...

  3. 海量数据去重的Hash与BloomFilter学习笔记

    文章目录 知识框架 背景 例子 平衡二叉树 散列表 介绍 hash函数 选择hash的经验 负载因子 冲突处理 布隆过滤器 介绍 组成 原理 为什么不支持删除操作? 应用场景 应用分析 如何确定n和p ...

  4. 海量数据去重,hash、布隆过滤器以及hyperloglog丨c/c++linux服务器开发丨后端开发丨Linux后台开发丨底层原理

    海量数据去重,hash.布隆过滤器以及hyperloglog 视频讲解如下,点击观看: 海量数据去重,hash.布隆过滤器以及hyperloglog丨c/c++linux服务器开发丨后端开发丨Linu ...

  5. Java Web和Java后端学习之路

    摘要: 每个阶段要学习的内容甚至是一些书籍.针对Java Web和Java后端开发 java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的 ...

  6. 【实验室培训】大学生的Java后端开发学习之路(从App开发讲起)

    文章目录 前言 一.浅谈如何开发一款App 1.一个好的idea 2.根据这个idea完善好具体的需求 3.分工合作 4.设计阶段 ①UI设计 ②接口设计 ③架构设计 5.开发阶段 6.测试阶段 7. ...

  7. 2021年后端学习路线书籍-自我进阶之路

    最近也有不少小伙伴们在公众号发消息问我,如何去学好一门后端语言?怎么才能进阶?在公司如何才能快速的晋级晋升?你作为一个后端是如何学习的呢? 其实我正儿八经的工作也就 4 年多了,但是如果算上大三实习大 ...

  8. 我的mongo学习之路

    mongo学习之路 mongodb的安装,在这里就不做介绍了,不管是windows还是mac,网上都有教程,可以自行学习一下~~~ 一.启动 mongod 复制代码 二.链接 mongo 复制代码 三 ...

  9. pyqt5从子目录加载qrc文件_【JVM系统学习之路】一篇看懂类加载

    JVM系统学习之路系列演示代码地址:https://github.com/mtcarpenter/JavaTutorial 嗨喽,小伙伴大家好,我是小春哥,今天是打卡 [JVM系统学习之路] 的第二篇 ...

最新文章

  1. 和12岁小同志搞创客开发:如何选择合适的传感器?
  2. 量子力学工具箱再添利器—科学家提出高效驱动微型引擎概念
  3. python 子图_python 实现在一张图中绘制一个小的子图方法
  4. SAP CRM产品主数据错误消息Product ID Not in valid range的分析方法
  5. 二叉树特性及详细例子
  6. 三年租男友回家竟花了10万......
  7. Apache Kafka / Spark流系统的性能调优
  8. Python学习12 文件的读写
  9. Gitbook+码云创建自己的文档
  10. leecode练习--942、增减字符串匹配
  11. VALSE学习(三):深度学习梯度讲解
  12. 设置php语言,PHP语言之php-fpm 基本设置与启动
  13. 团队博客-随笔:团队展示 (科利尔拉弗队)
  14. PyCharm中的一些设置
  15. 为什么技术面过了却挂在了HR面试之”谈谈你的职业生涯规划“
  16. JS 字符串 常用方法(截取、替换、拼接)
  17. 深夜,想到今天学的linux内容,太值了
  18. 交叉编译-20:gettext移植到君正平台
  19. 无人驾驶避障方法研究
  20. 计算机数控系统cnc分类,数控机床系统有几种 数控系统的类型和分类

热门文章

  1. vba编写kml圆思路
  2. 拦不住灰犀牛,芯片短缺即将扭转,小型公司风险骤增!
  3. log4j:WARN No appenders could be found for logger 解决办法
  4. 最火的android开源项目(二)
  5. logistic回归模型评估-R实现
  6. mysql存储过程备份_mysql-数据备份与存储过程
  7. mysql phpmyadmin 文件夹_PHPMyadmin 配置文件详解(配置)
  8. 上海市高等学校信息技术水平考试——二三级人工智能技术及应用
  9. 集线器(Hub)、交换机(SW)、路由器(router)对比区别
  10. 数字可调电源电路实现