盘一盘 6 个海量数据面试题
共 3331字,需浏览 7分钟
·
2022-03-08 01:59
近期看到群里有小伙伴面试遇到了大数据类的题目,这类题目也是面试中比较高频的,今天给大家整理了一些海量数据类的超高频面试题目。
这里选取6个为例,给大家分享一下。
什么是海量数据?
所谓海量数据处理,就是指数据量太大,无法在较短时间内迅速解决,或者无法一次性装入内存。
而解决方案就是:
针对时间,可以采用巧妙的算法搭配合适的数据结构,如 Bloom filter/Hashmap/bit-map/堆/数据库/倒排索引/Trie树; 针对空间,大而化小,分而治之(hash映射),把规模大化为规模小的,各个击破。
[海量数据]处理的基本方法总结起来分为以下几种:
分而治之/hash映射 + hash统计 + 堆/快速/归并排序; Trie树/Bloom filter/Bitmap 数据库/倒排索引; 双层桶划分; 外排序; 分布式处理之Hadoop/Mapreduce
1、海量日志数据,统计出某日访问[百度]次数最多的那个IP
解决方式:IP地址最多有 2^32 = 4G 种取值情况,所以不能完全加载到内存中进行处理,采用 hash分解+ 分而治之 + 归并的方式:
(1)按照 IP 地址的 Hash(IP)%1024 值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件最多包含4MB个IP地址;
(2)对于每一个小文件,构建一个IP为key,出现次数为value的Hash map,同时记录当前出现次数最多的那个IP地址
(3)然后再在这1024组最大的IP中,找出那个频率最大的IP
2、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
解决思想:hash分解+ 分而治之 + 归并
(1)顺序读文件中,对于每个词x,按照 hash(x)/(1024*4) 存到4096个小文件中。这样每个文件大概是250k左右。如果其中有的文件超过了1M大小,还可以按照hash继续往下分,直到分解得到的小文件的大小都不超过1M。
(2)对每个小文件,可以采用 trie树/hashmap 统计每个文件中出现的词以及相应的频率,并使用 100个节点的小顶堆取出出现频率最大的100个词,并把100个词及相应的频率存入文件。这样又得到了4096个文件。
(3)下一步就是把这4096个文件进行归并的过程了
3、有a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
解决方案1:hash 分解+ 分而治之 + 归并 的方式:
如果内存中想要存入所有的 url,共需要 50亿 * 64= 320G大小空间,所以采用 hash 分解+ 分而治之 + 归并 的方式:
(1)遍历文件a,对每个 url 根据某种hash规则,求取hash(url)/1024,然后根据所取得的值将 url 分别存储到1024个小文件(a0~a1023)中。这样每个小文件的大约为300M。如果hash结果很集中使得某个文件ai过大,可以再对ai进行二级hash(ai0~ai1024),这样 url 就被hash到 1024 个不同级别的文件中。
(2)分别比较文件,a0 VS b0,…… ,a1023 VS b1023,求每对小文件中相同的url时:把其中一个小文件的 url 存储到 hashmap 中,然后遍历另一个小文件的每个url,看其是否在刚才构建的 hashmap 中,如果是,那么就是共同的url,存到文件中。
(3)把1024个文件中的相同 url 合并起来
解决方案2:Bloom filter
如果允许有一定的错误率,可以使用 Bloom filter。
4G内存大概可以表示 340 亿bit,n = 50亿。
如果按照出错率0.01算需要的大概是650亿个bit,现在可用的是340亿,相差并不多,这样可能会使出错率上升些。
将其中一个文件中的 url 使用 Bloom filter 映射为这340亿bit
然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)
4、有10个文件,每个文件1G,每个文件的每一行存放的都是用户的 query,每个文件的query都可能重复。要求你按照query的频度[排序]
解决方案1:hash分解+ 分而治之 +归并
(1)顺序读取10个文件 a0~a9,按照 hash(query)%10 的结果将 query 写入到另外10个文件(记为 b0~b9)中,这样新生成的文件每个的大小大约也1G
(2)找一台内存2G左右的机器,依次使用 hashmap(query, query_count) 来统计每个 query 出现的次数。利用 快速/堆/归并排序 按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件c0~c9。
(3)对这10个文件 c0~c9 进行归并排序(内排序与外排序相结合)。每次取 c0~c9 文件的 m 个数据放到内存中,进行 10m 个数据的归并,即使把归并好的数据存到 d结果文件中。如果 ci 对应的m个数据全归并完了,再从 ci 余下的数据中取m个数据重新加载到内存中。直到所有ci文件的所有数据全部归并完成。
解决方案2:Trie树
如果query的总量是有限的,只是重复的次数比较多而已。
可能对于所有的query,一次性就可以加入到内存了。
在这种情况下,可以采用 trie树/hashmap 等直接来统计每个query出现的次数,
然后按出现次数做快速/堆/归并排序就可以了。
5、在 2.5 亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。
解决方案1:hash 分解+ 分而治之 + 归并
(1)2.5亿个 int 类型 hash 到1024个小文件中 a0~a1023,如果某个小文件大小还大于内存,进行多级hash
(2)将每个小文件读进内存,找出只出现一次的数据,输出到b0~b1023
(3)最后数据合并即可
解决方案2 :2-Bitmap
如果内存够1GB的话,采用 2-Bitmap 进行统计,共需内存 2^32 * 2bit = 1GB内存。
2-bitmap 中,每个数分配 2bit(00表示不存在,01表示出现一次,10表示多次,11无意义)
然后扫描这 2.5 亿个整数,查看Bitmap中相对应位,如果是00,则将其置为01;如果是01,将其置为10;如果是10,则保持不变。
扫描完成后,查看Bitmap,把对应位是01的整数输出即可。(如果是找出重复的数据,可以用1-bitmap。第一次bit位由0变1,第二次查询到相应bit位为1说明是重复数据,输出即可)
6、现有两个各有20亿行的文件,每一行都只有一个数字,求这两个文件的交集。
解决方案:采用 bitmap 进行问题解决,int 的[最大数]是 2^32 = 4G。
用一个二进制的下标来表示一个 int 值,大概需要4G个bit位,即约4G/8 = 512M的内存,就可以解决问题了。
① 首先遍历文件,将每个文件按照数字的正数,负数标记到2个 bitmap 上,为:正数 bitmapA_positive,负数 bitmapA_negative
② 遍历另为一个文件,生成正数:bitmapB_positive,bitmapB_negative
③ 取 bitmapA_positive and bitmapB_positive 得到2个文件的正数的交集,同理得到负数的交集。
④ 合并,问题解决
这里一次只能解决全正数,或全负数,所以要分两次