海量数据处理--互联网公司偏爱的考题

  百度的笔试、一面、二面,豆瓣的笔试题都涉及到了海量数据处理;因为不是CS专业,平时真心没用过上亿的数据量,初看到题的时候完全无从下手,顶多就一些将数据分割成很多的小文件,然后处理这些单个的文件,最后进行归并,而实现的过程也不是很清楚。

  仔细回想一下《编程诛讥》里是有提到过海量数据处理的,只是当时连Bitmap都不清楚,就没有细心研究过。昨天百度一面的一道题,说有10亿个无符号的整型数据,如何找出重复的数字并统计其个数。当时,我又将“分割”的算法照搬一遍,还加上Quicksort,后面发现,归并的时候不知道怎么处理了;只好换一种思路,想到了计数排序,考官一开始没听懂,问我是不是桶,我一想,就是这个了;只要内存足够大,就可以直接放入桶里面,当时我说一共需要2^32+k(k是最大的那个数)个桶,但考官说为什么要这么多呢,10亿个行不行,以我的理解,就只有这么笨的方法,优化什么的真不晓得了。现在,考官大哥人还满nice的,不会的都尽量会提醒我,也不会摆架子,或许百度这种高富帅公司的环境就这样吧。

  下面的几个题,也经常见到,也是最近才看到的,觉得非常不错。借用一句话,It's just technology , not magic.只要用心学,那些我们看似很神奇、很难的东西也就不过如此而已。

1、海量日志数据,提取出某日访问百度次数最多的那个IP。
  此题,在我之前的一篇文章算法里头有所提到,当时给出的方案是:IP的数目还是有限的,最多2^32个,所以可以考虑使用hash将ip直接存入内存,然后进行统计。
  再详细介绍下此方案:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有个2^32个IP。同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率最大的几个)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。
  2、搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
  假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
  典型的Top K算法,还是在这篇文章里头有所阐述。 文中,给出的最终算法是:第一步、先对这批海量数据预处理,在O(N)的时间内用Hash表完成排序;然后,第二步、借助堆这个数据结构,找出Top K,时间复杂度为N‘logK。 即,借助堆结构,我们可以在log量级的时间内查找和调整/移动。因此,维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比所以,我们最终的时间复杂度是:O(N) + N'*O(logK),(N为1000万,N’为300万)。ok,更多,详情,请参考原文。
  或者:采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。
  3、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
  方案:顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为x0,x1,...x4999)中。这样每个文件大概是200k左右。
  如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M。 对每个小文件,统计每个文件中出现的词以及相应的频率(可以采用trie树/hash_map等),并取出出现频率最大的100个词(可以用含100个结点的最小堆),并把100个词及相应的频率存入文件,这样又得到了5000个文件。下一步就是把这5000个文件进行归并(类似与归并排序)的过程了。
  4、有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
  还是典型的TOP K算法,解决方案如下: 方案1: 顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为)中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。 找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件(记为)。
  对这10个文件进行归并排序(内排序与外排序相结合)。
  方案2: 一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。
  方案3: 与方案1类似,但在做完hash,分成多个文件后,可以交给多个文件来处理,采用分布式的架构来处理(比如MapReduce),最后再进行合并。

  

posted on 2012-10-22 23:04  CodeAnt  阅读(233)  评论(1编辑  收藏  举报