上周面试开场就被问到一个海量数据处理的问题,之前没有认真思考过,基本没有答到点上,看了结构之法的教你如何迅速秒杀掉:99%的海量数据处理面试题,我也来回顾一下,欢迎大家探讨。
【问题】:有一个200亿个记录的文件,每个记录是64位的数,现需要统计某个数在文件中出现的次数,并且需要插入删除某个数,可用内存180MB,该怎么处理?
我的解决思路:
预处理:
①:大而化小。将大文件hash取模,分成M个小文件(M根据可用的内存大小设定)
②:统计。分别统计每个小文件中每个数出现的次数。采用hash_map(或用rb_tree实现的map)统计频率,得到
M个
新的小文件。
③:
M的取值。200亿个64位数大小约为1.6TB,分布均匀的情况下,M=2^14时,预处理第一步后小文件大小约为160MB,考虑到预处理第二步采用
(key,value)对来
记录频率,文件可能扩大,可以将M设为2^15,保证最终的小文件不大于180MB。
查插删改操作:
① 找某个数出现的次数:对这个数取模M,找到对应的统计文件,将该文件加载到内存,查找该这个数出现的次数,时间复杂度为O(1)(rb_tree为O(logn))。
② 插删改类似上述处理
。
其他考虑因素:
① 若文件记录分布不均匀,分割后某些文件仍非常大?
对较大的文件继续分割,分割三次即可将文件中记录的范围缩小到512KB(2^64/2^45),若三次分割后文件还大于180MB,说明这个范围内的数存在一个或多个数有大量的重复,直接分多次读取该文件,按照预处理第二步统计各个数出现的次数输出到新文件即可。
② 若插入数据后,文件超过180MB该怎么处理?
将该文件分割成两个文件。如果是用hash_map,则将该文件记录模2分成来个两个文件,如果是用rb_tree,则将左子树+根和右子树分到两个文件。
由于没有实际经验,如果上面的方法存在问题,欢迎有经验的朋友提出建议。