常见大数据和空间面试题

过滤100亿黑名单

题目

假设有100亿个URL的黑名单,每一个URL最多占用64B,设计一个过滤系统,判断某条URL是否在黑名单里。数据库

要求

不高于万分之一的判断失误率;额外内存不超过30GB数组

答案

100亿个64B的URL须要640GB的内存,显然直接存哈希表不合理。考虑布隆过滤器,假设有一个长度为m的bit类型数组,如图所示:缓存

clipboard.png

输入阶段:分布式

有k个哈希函数,函数的输出域S大于或等于m,假设哈希函数彼此独立,对于同一个输入(以字符串表示的URL),通过k个哈希函数的计算结果也是相互独立。对计算的每个结果Mod m,将bit array上对应的位置置1,以下:memcached

一个输入对象会将bitmap某些位置涂黑,处理完全部输入对象,会将bitmap至关多位置涂黑,至此,布隆过滤器生成完毕,表明以前全部输入对象的集合。函数

clipboard.png

20亿个数中出现最多的数

问题

包含20亿个全是32位整数的大文件,在其中找出出现次数最多的数。spa

要求

内存限制:2GB设计

答案

将20亿个数用hash函数分红16个文件。而后统计每一个小文件中,哪一个数字出现次数最多。最后再比较每一个小文件的次数最多的数。(本题分红16个也是根据题目来的。考虑最极端状况。20亿个数都不一样)32位的整数要占4b,key占4b,value占4b。共8b。内存只有2G。因此大概每一个小文件存2亿条。就须要10个小文件。可是hash函数必须2的n次方。因此2的4次方。16个对象

40亿个数找没出现的数

问题

有一个包含40亿个无符号整数的文件,最多使用1GB内存,找到全部没出现的数blog

分析

最差状况,40亿个数都不一样,哈希表保存出现过的数,须要内存4B*40亿,大约16GB内存。

答案

使用bitmap,申请一个长度为4294967295bit类型的bitArray,每一个位置只表示0或1,该数组占用空间约500MB。遍历这20亿个数,例如遇到7000,就将bitArray[7000]置1。遍历完成后,再依次遍历bitArray,哪一个位置没有置1,哪一个数就不在40亿个数中。

40亿个数找第一个没出现的数 。内存只有10M

答案

具体的,第一次遍历,申请长度64的整形数组countArr[0...63],统计每一个区间计数增长。例如,当前数是34225522090,34225522090/67108864=51,countArr[51]++。遍历完以后,一定有一个countArr[i]小于67108864,表示i区间内至少有一个数没出现过。此时countArr[]使用的内存是64*4B。

假设在37区间有一个数没出现,申请一个长度为67108864的bitmap,内存大约8MB,记为bitArr[0~67108863]。再一次遍历40亿个数,只关心37区间的数,记为num。将bitAry[num-6710886437]的值置位1。遍历完以后,bitArr必然有没有置1的位置,记为i,则6710886437+i就是没出现过的数。

找出100亿个重复URL以及搜索词汇topK问题

问题

有一个包含100亿URL的大文件,每一个URL占64B,找出重复URL;补充,找出top100搜索词汇

常规答案

  1. 大文件经过哈希函数分配到不一样机器
  2. 哈希函数将大文件拆分红小文件。

对于每个小文件,利用哈希表遍历,找出重复的URL,或者分给机器或拆分文件完以后,进行排序,看是否有重复的URL。

补充问题的思路也是经过哈希函数分流,对于每一个小文件,简历词频哈希表,建一个大小为100的小根堆,选出每一个小文件的top100.每一个小文件的top100进行外排序或者接着使用小根堆,就能获得100亿数据的top100.

出现两次的数以及中位数问题

问题

有40亿个无符号32位整数,最多可使用1GB内存,找出全部出现了两次的数;补充问题,最多使用10MB内存,找到40亿个数的中位数

答案

第一个问题能够用bitmap作,申请长度为2?232bit的bitArr,2个bit表示一个数出现的词频。遍历40亿个数,假设出现num,将bitArr[2num]和bitArr[2num+1]设置为01,第二次出现,设置为10,第三次,设置为11。之后再遇到11的,就不作处理。遍历完成后,再遍历一次,若发现bitArr[2num]和bitArr[2num+1]是10,则num是出现了两次的数。

第二个问题,分区间讨论。长度为2MB的unsigned int数组占用8MB,将区间数目定位232/2M,取整为2148个区间,第0区间0~2M-1,第i区间2Mi~2M(i+1)-1

申请一个长度为2148的unsigned int整数数组arr[0..2147],arr[i]表示i区间有多少个数,arr占用内存小于10MB。遍历40亿个数,当前数num为num,落在区间(num/2M),对应arr[num/2M]++。累加统计每一个区间的累计数目,就能找到40亿个数的中位数。例如0~K-1区间数目个数为19.998亿,加上第K个区间就超过了20亿,说要中位数必定在K区间中,而且必定是第K区间的第0.002亿个数。

接着申请长度2M的unsigned int数组countArr[0..2M-1],占用8MB。遍历40亿个数,只关心第K区间的数numi,countArr[numi-K*2M]++。统计完以后在第K区间找地0.002亿个数字便可。

一致性哈希

分布式数据库集群缓存,例如memcached,将数据的id经过哈希函数转换为key,假设有N个机器,计算key%N,获得及其所属编号,增删改查都在这台机器上。一致性哈希能在机器扩容(N发生变化),使得不用从新计算一遍key%N

三台机器处于哈希环,id经过哈希映射为key,在哈希环中顺时针找距离最近的机器。

机器较少的时候可能会出现负载不均衡,如图所示:

答案

引入虚拟节点,增长结点数

相关文章
相关标签/搜索