大数据处理小结
1.从海量数据中找出中位数
题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。
只写出思路即可。
方案1:网上的解法都是千篇一律,方法都是将整数分段,映射都n个区间段,然后对
每个区间段计数,当curSum>5G的时候停止计数,并统计中位数所在区间的每个取值的个数
进行第二次统计,这样就得到了第5G大的数据了,这个的确是个好方法吧,算法的
时间复杂度是线性的,因为是遍历了两次数据。
方案2:采用编程之美上的一个思路,我们无法将5G的数据装入内存,那么就转入相对小的数据。
比如取k为2G,我们利用最大堆,找出第2G大的数据,然后再遍历一次,找到第4G大的数据,然后建立1G大
的堆,找到第5G大的堆,每次时间为nlogk,需要扫描[K/k]次。
2.寻找前K个词
对于海量数据“寻找前K大”,目前总结起来我想一般也就两种方案:堆排序、K选择。
a 堆排序这个没什么好说的,复杂度为O(nlogk)
b 利用快排的思想,每次我们都是从轴那个地方选择比它大的那一半数据进行查找,直到剩余元素和K大不了多少是,
利用基本排序取前K,这样复杂度为O(n+1/2*n+1/4+n+...+1/(n/k)*n)=O(2*n).和问题规模是线性关系的。
它的常数因子较堆排序更小一些。
下面是从网上看到的很多大数据处理的面试题总结的一些小技巧:
处理这方面的问题我们可能会想到的方法为:
hashmap,堆,桶(区间计数),trie树,归并,快排,bit-map,bloom Filter.例外还有些高级的方法,map-reduce,倒排索引(这个好像
和搜索引擎中关键词的查询密切相关).
下面是一个经典的例子,附有牛神的分析:
上千万or亿数据(有重复),统计其中出现次数最多的前N个数据,分两种情况:可一次读入内存,不可一次读入。
解法:
可用思路:trie树+堆,数据库索引,划分子集分别统计,hash,分布式计算,近似统计,外排序
所谓的是否能一次读入内存,实际上应该指去除重复后的数据量。如果去重后数据可以放入内存,我们可以为数据建立字典,比如通过 map,hashmap,trie,然后直接进行统计即可。当然在更新每条数据的出现次数的时候,我们可以利用一个堆来维护出现次数最多的前N个数据,当然这样导致维护次数增加,不如完全统计后在求前N大效率高。
如果数据无法放入内存。一方面我们可以考虑上面的字典方法能否被改进以适应这种情形,可以做的改变就是将字典存放到硬盘上,而不是内存,这可以参考数据库的存储方法。
当然还有更好的方法,就是可以采用分布式计算,基本上就是map-reduce过程,首先可以根据数据值或者把数据hash(md5)后的值,将数据按照范围划分到不同的机子,最好可以让数据划分后可以一次读入内存,这样不同的机子负责处理各种的数值范围,实际上就是map。得到结果后,各个机子只需拿出各自的出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是reduce过程。
实际上可能想直接将数据均分到不同的机子上进行处理,这样是无法得到正确的解的。因为一个数据可能被均分到不同的机子上,而另一个则可能完全聚集到一个机子上,同时还可能存在具有相同数目的数据。比如我们要找出现次数最多的前100个,我们将1000万的数据分布到10台机器上,找到每台出现次数最多的前 100个,归并之后这样不能保证找到真正的第100个,因为比如出现次数最多的第100个可能有1万个,但是它被分到了10台机子,这样在每台上只有1千个,假设这些机子排名在1000个之前的那些都是单独分布在一台机子上的,比如有1001个,这样本来具有1万个的这个就会被淘汰,即使我们让每台机子选出出现次数最多的1000个再归并,仍然会出错,因为可能存在大量个数为1001个的发生聚集。因此不能将数据随便均分到不同机子上,而是要根据hash 后的值将它们映射到不同的机子上处理,让不同的机器处理一个数值范围。
而外排序的方法会消耗大量的IO,效率不会很高。而上面的分布式方法,也可以用于单机版本,也就是将总的数据根据值的范围,划分成多个不同的子文件,然后逐个处理。处理完毕之后再对这些单词的及其出现频率进行一个归并。实际上就可以利用一个外排序的归并过程。
另外还可以考虑近似计算,也就是我们可以通过结合自然语言属性,只将那些真正实际中出现最多的那些词作为一个字典,使得这个规模可以放入内存。
下面是一些有代表性的面试题目:
http://www.cnblogs.com/buptLizer/archive/2011/09/13/2175116.html
http://www.cnblogs.com/buptLizer/archive/2011/09/13/2175120.html