python_19_哈希函数、布隆过滤器、一致性哈希、并行和资源限制

资源限制问题一般不会手撕代码

1 认识哈希函数:

  1. 输入参数data,假设是int类型,特征:可能性无穷大,比如str类型的参数
  2. 输出参数类型out,特征:可能性可以很大,但一定是有穷尽的
  3. 哈希函数没有任何随机的机制,固定的输入一定是固定的输出,相同的输入一定会是相同的输出,不同的输入导致输出离散化而不相同
  4. 输入无穷多但输出值有限,所以不同输入也可能输出相同(哈希碰撞,很少发生)
  5. 再相似的不同输入,得到的输出值,会几乎均匀(离散和均匀一个道理)的分布在out域上(重点)
  6. 输出结果取余也是均匀分布,碰撞后厚度也是均匀分布。
    扩容logN次

桶里面放有序数据,可以用哈希值排序

2 布隆过滤器

布隆过滤器:没有删除的黑名单系统
应用场景:有病毒网站进黑名单,可在黑名单查询该网站是否用户能进?爬虫爬取,是否爬取过这个网站?
好处:建立黑名单并且可以节省空间
节约空间。

  1. 利用哈希函数的性质
  2. 每一条数据提取特征
  3. 加入描黑库

2.1 原理

位图原理:
一个状态就是一个bit
位图有m个长度,实际的使用空间是m/8的字节数。

# 位图实现
# 位图实现
# 3200  bit   bit[0~3199]
arr = [0] * 100   # 数组里面一位数为32bit
# arr[0] -> 32bit int 0(int)
# arr[1] -> 32bit int 0(int)
position = 453
# arr[int(453/32)] = arr[14] -> 010101000101  0  11010   32位
# 为了提取(453%32) = 5 ,提取第5位状态  第0位开始数  第5位是0
# arr[14] >> 5    010101000101  0  11010  >> 5  整体右移5位,0就来到最右侧
# 最右侧和1与一下,0 & 1 = 0
# arr[int(453/35)]  向右移动 (453%32) 这么多位置  和1与一下,就知道状态是0还是1
status = ((arr[int(453/32)] >> (453%32)) & 1)  # 得出543位的状态了

# 453位的状态设置为1,一定改变这个数字某一位状态
# 453在哪个数上  453/32位置上
# 1向左移动5位,   1 << (453 % 32) 只在第5位上有1
# 或 原始数,就将453位设置为1
arr[int(453/32)] = arr[int(453/32) | (1 << (453 % 32))]


  --------------------------------------------------

# 为了装更大的位数,可以用二维数组
# 32000bit
# matrix[0] -> 100 3200  列有100,每一个32位,行有100
matrix = ([0] * 100 for _ in range(100))

position = 170039
# 170039 在  170039 / 3200 这一行
# 在53行第几个数 170039 % 3200 是剩余的比特位 ,对剩余的bit位  /32 就是这一行第几个数字  %32 就是定位第几个bit
# 下标不够用,通过这种方式扩展


2.2 过滤器原理

先创建一个都是0的m长位图,某个位置变成就就当成描黑的状态。
url算出哈希值%m得到一个值,这个值代表位图位置,将位图该位置描黑;该url再取另一个哈希函数算出哈希值%m,再对位置描黑。如果有k个哈希函数,就会描黑k个位置,有可能k个位置是重的,就说明url加入了黑名单。
用k个哈希函数%m,算出k个位置,如果这些位置都是黑,说明此url是黑名单中。

k个哈希值描黑是特征,混在一起是为了省空间。

存在问题:

  1. 选几个哈希函数合适(k)?
  2. 位图到底选多大(m)?

不需要知道单样本大小,由样本数量决定m大小。

有失误率的:100亿个url描1000长度位图,估计都能描黑。
比如:爬数据,可以允许失误,少爬一个数据。
不是黑名单的东西可能误报黑名单,但是黑名单的一定会报告黑名单。
黑名单必须先给,不能超过什么量。可以动态来,爬虫就是动态的。

2.3 布隆过滤器设计

布隆过滤器只需要知道,样本量N和失误率P。
设计出的过滤器只能失误率比P低。
选个合适的m,既省空间,也能保证失误率低,不需要无限增加m。
在这里插入图片描述
在这里插入图片描述

M和N已经确定,K和失误率P的关系,K太多了,描黑的就多了,m会迅速耗尽。
在这里插入图片描述
m有理论值,实际值(面试官给的),公式都用理论值。
p真实的失误率公式。
在这里插入图片描述

2.4 得到K个哈希函数

怎么得到k个哈希函数,又要求彼此独立。
比如凑13个哈希函数,用两个哈希函数(f和g)就够用了。
在这里插入图片描述
f哈希函数返回值+1g哈希函数返回值->第一个哈希函数
f哈希函数返回值+2
g哈希函数返回值->第二个哈希函数
可以构造无数个哈希函数并且彼此独立。

2.5 某产品用到此过滤器

hafs系统用得到这个,做文件分布式系统,很多小文件,通过哈希把数据分配到小文件,小文件有值或有重复的值。hafs会把每个文件分别建立小过滤器,看看str哪些小文件里面描黑,如果是白的肯定不存在记录,描黑的估计有,把描黑的都搜索一遍。

3 一致性哈希问题

分布式存储结构最常见结构:一致性哈希
解决:数据分布式存储方案->设计key多一些
关键技术:

  1. 哈希域变成环的设计
  2. 虚拟节点技术

一致性哈希没有了除余的过程,都是裸哈希值

3.1 情况

3台机器[7哈希值,100亿哈希值,2000亿哈希值]分别对应a,b,c三台机器。
算abc哈希值,算出10以后,找最近的在有序表找>=10最左的位置,属于b机器。
算出3000亿,归属于a。
在这里插入图片描述
归属知道后,有两个问题:
一开始没办法做到均分。
突然加一个减一个机器就不均方了,这就解决不了负载均衡问题。

3.2 虚拟节点技术,按比例抢环

m1,m2,m3三台机器,用人为(字符串)分配的方案分配给这三台机器。
比如给m1分配到1000个字符串…
用3000个字符串,用3000个虚拟节点去抢环位置,抢到以后归给自己机器。
在这里插入图片描述
4000亿以上数据才可能出现哈希碰撞。


两个虚拟节点给数据或迁移数据,只用在后台写虚拟节点怎么迁移对应到时机就可以了。
m4,给它新1000去夺数据,依然均衡。
虚拟节点只用量控制就行。
下线机器,也能按比例分。
例子:香水喷到屋子里,不同香水味占比不同,去掉一种香水味,剩下香水也是均匀占比。


一些问题:
m1性能好,m2和m3性能一般
就给m1分配2000个,给m2 m3各分配1000个
负载均衡和辅助管理都能做到

虚拟节点数量,就是抢到的实际数据量

3.3 亚马逊物流仓库

一个人在北京,怎么设计这个人在方圆5公里内,这些店推荐到手机上,这些店是存在的。

3.3.1 解决

整个城市认为是一个大网格,每一公里画一个方块
,以天安门为中心扩散出去,给北京经度纬度都在一个方块上,每一个网格可以得到行号和列号。

把每个商家数据库(名称、经纬度等等),再加一个数据,属于哪个格子,这个格子编号是什么,行号和列号,作为数据库字段就行。
pic1

请添加图片描述

如果人在某个经纬度,也可以定位一个格子,可以找到附近的格子,可以直接生成附近的格子
pic2

在这里插入图片描述

4 并行算法

4.1 岛问题

一个只有0和1两种数字的二维矩阵中,上下左右能练成一片的1,算一个岛返回矩阵中,一共有几个岛。

4.1.1 单内存单CPU

代码:时间复杂度O(N*M),已经很简洁了

def countIslands1(m):
    if m is None or m[0] is None:
        return 0
    N = len(m)      # 行
    M = len(m[0])   # 列
    res = 0
    # 感染行为后,1变2,有多少个不连成1片的1去感染,就是岛的数量
    for i in range(N):   # 每一行每一列,每个位置都遍历
        for j in range(M):
            if m[i][j] == 1:       # 这个位置如果是1,连城
                res += 1           # 增加一个岛的数量
                infect(m,i,j,N,M)  # 连成一篇的1都会变成2,遇到感染的点会跳过
    return res

# 感染函数infect
# 来到 ij位置,如果它是1,把它上下左右所有的路,1所到之处全部变成2
# N表示有多少行(固定)
# M表示有多少列(固定)
def infect(m,i,j,N,M):  # 从ij出发,所有连成一片的1全变成2
    # ij如果越界 或 此位置是非1,直接返回
    if i < 0 or i >= N or j < 0 or j <= M or m[i][j] != 1:
        return
    m[i][j] = 2
    # 上下左右去感染
    infect(m,i + 1,j,N,M)
    infect(m,i - 1,j,N,M)
    infect(m,i,j + 1,N,M)
    infect(m,i,j - 1,N,M)

主流程会碰一次位置,1变成2碰一次位置,邻居调用碰4次
但是大图,中国地图,01表,所以需要用并行算法

4.2 并行算法解释

4.2.1 打断

要用到并查集算法,并查集用法是查某两个事物,合成一个集合都是O(1).
在这里插入图片描述
这个大图岛的数量一共是一个。

这么大的图,一个cpu跑不了,需要用两个cpu,所以中间要分割图。
分割开以后只能产生更多的岛,不可能减少。

4.2.2 处理打断

在感染过程中,一方面要求岛的数量,另一方面要把自己右边界的1,是哪个感染的感染来的,记下来。
行号和列号可以表示一个位置。

看看有没有右边界处变2的点,有点就记录一下,记录为这是A感染点感染到的。
在这里插入图片描述

第二块cpu记录左边界感染来的
跑完后,左边两个岛,右边两个岛,边界的信息全有。
在这里插入图片描述
一共4个感染点ABCD,都是一个独立集合。
关注边界处左边是感染点右边是感染点的地方。
A和C应该合在一块,所以岛数-1,集合{AC}
B和C应该在一块,岛数-1,集合{ABC}
B和D连在一起,岛-1,{ABCD}
A和D已经连在一起了,岛数不-1,整体就1个岛了。
合并用并查集算法

在这里插入图片描述
先16个cpu,然后两两合并就变成8个cpu,再合并变成4个cpu,2,1个cpu
每次合并都把边界信息向下传递,并查集信息留着,所有区域共用一个并查集。
某两块cpu和的适合用公共cpu,每个岛的位置必然不一样,并查集都不用做线程安全。

5 资源限制技巧汇总(已全)

  1. 布隆过滤器用于集合的建立与查询,并可以节省大量空间;
  2. 一致性哈希解决数据服务器的负载管理问题;
  3. 利用并查集结构做岛问题的并行计算;
  4. 哈希函数可以把数据按照种类均匀分流;
  5. 位图解决某一范围上数字的出现情况,并可以节省大量空间,因为一个比特表示一个数;
  6. 利用分段统计思想、并进一步节省大量空间;
  7. 利用堆、外排序来做多个处理单元的结果合并

6 资源限制题目

6.1 题目1

32位无符号整数的范围是0~4,294,967,295,现在有一个正好包含40亿个无符号整数的文件,可以使用最多1GB的内存,怎么找到出现次数最多的数?

看标题2的位图

6.2 题目2

32位无符号整数的范围是0~4,294,967,295,现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然存在没出现过的数。
可以使用最多1GB的内存,怎么找到所有未出现过的数?【进阶】
内存限制为10MB,但是只用找到一个没出现过的数即可
内存限制为3KB,但是只用找到一个没出现过的数即可
内存限制为三个变量,但是只用找到一个没出现过的数即可

思路:
42亿的量,每一个无符号整数是4字节,需要(10亿字节空间是1G)16G空间。
但是只用1G的空间,就用位图算法。
2的32次方是比特数,0表示没出现过,1表示出现过。最多需要2的32次方比特,就能知道0~2的32次方-1范围内的数出现过没有。
哈希表是4个字节表示一个数出现没出现过,位图是1个比特表示一个数出现没有出现过。
16G/32 = 500多M,够用了。
把每次放一个整数的哈希表替换成比特数组,表示任何一个数字出现没出现过。

6.2.1 内存限制为10MB

内存限制为10MB位图也做不了了。

3kb都做成整型数组能做多大?
整型数组一个4字节,3kb/4=3*1024/4 = 768

找离768最近的2的某次方,是512,是2的9次方

数组定位512长度,[512] 一定不会爆
counts[512],counts数组有512空间
整个数的范围是0~2的32次方-1,总共有2的32次方这么多数字,数组有512份,2的32次方一定能被均分为512份,刻意找的2的某次方是512,2的32/2的9 必能均分。

均分一个数是多少2的32 / 512 = 8388608
每一份8388608这么多数字。
第0份去统计0~8388608这个范围上数字出现了几个。
让第2份去统计8388609~8388609*2这个范围上数字出现了几个。
遍历所有的数组,哪一个数它中了哪个范围,就在counts数组里++。
num/8388608 = 哪一份,在第i个份,counts[i]++,统计词频。

比如遍历40亿个数,如果这个数是50515,在0~8388608这个范围,50515/8388608 = 0,所以在第0份,那么counts[0]++。
既然遍历40亿个数,那么数字肯定不够42亿,必有某一份数字量会少,此范围必缺数字。
找到那个范围L…R,继续用3kb分出512份,一直分,直到分到某个范围可以用3kb做所有比特类型的数组,统计哪个数出没出现过。

思路,给一个空间,要把它分成片

6.2.2 内存限制为三个变量

用二分查找,mid在某个位置
看看左右侧词频,左边词频是2的31次方,右侧也是
遍历40亿个数
左侧右侧必有不满,左侧超过2的31次方,右侧肯定不满
M+1 = L,mid再遍历文件,必有不满,分下去就找到了
方法不马上,最多二分32次搞定

在这里插入图片描述
假设右侧不够2的31次方
必然有一侧不够2的30次方
在这里插入图片描述

6.3 题目3

32位无符号整数的范围是0~4294967295,现在有40亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。

思路:将两个比特位表示数字出现过没有,出现过0次,为00
出现过1次,为01
出现过2次,为10
出现过3次,为11
大于3次全是11,所以题目也不能查出现4次。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
布隆过滤器是一种用于快速判断一个元素是否可能存在于一个集合中的数据结构。它可以通过牺牲一定的准确性来提高查询效率。布隆过滤器的主要应用之一就是解决数据一致性的问题。 在分布式系统中,数据一致性是一个重要的问题。当多个节点同时对数据进行更新时,可能会导致不同节点之间的数据不一致。为了解决这个问题,可以使用布隆过滤器来快速判断一个新的更新是否已经在其他节点上被处理过,从而避免重复处理。 具体来说,可以将每个节点维护一个布隆过滤器,用于记录已经处理过的更新。当一个节点接收到一个新的更新时,首先将更新的内容通过哈函数映射到布隆过滤器中的位数组上,并将相应位置置为1。然后,节点可以查询其他节点的布隆过滤器,判断该更新是否已经被其他节点处理过。 如果一个更新被多个节点同时接收到并处理,由于布隆过滤器的准确性有限,可能会存在误判的情况。这时可以通过其他机制来保证数据最终的一致性,比如使用分布式锁或者进行协调和同步。 总结起来,布隆过滤器可以在分布式系统中用于判断一个更新是否已经被其他节点处理过,从而解决数据一致性的问题。然而,布隆过滤器并不能保证完全的准确性,可能存在一定的误判率,需要结合其他机制来确保数据的最终一致性

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值