100亿个数字中找出最大的10个

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nameix/article/details/52016698

100亿个数字找出最大的10个

类似:
微信10亿用户中,获取红包最多的前100用户:

1、首先一点,对于海量数据处理,思路基本上是:必须分块处理,然后再合并起来。

2、对于每一块必须找出10个最大的数,因为第一块中10个最大数中的最小的,可能比第二块中10最大数中的最大的还要大。

3、分块处理,再合并。也就是Google MapReduce 的基本思想。Google有很多的服务器,每个服务器又有很多的CPU,因此,100亿个数分成100块,每个服务器处理一块,1亿个数分成100块,每个CPU处理一块。然后再从下往上合并。注意:分块的时候,要保证块与块之间独立,没有依赖关系,否则不能完全并行处理,线程之间要互斥。另外一点,分块处理过程中,不要有副作用,也就是不要修改原数据,否则下次计算结果就不一样了。

4、上面讲了,对于海量数据,使用多个服务器,多个CPU可以并行,显著提高效率。对于单个服务器,单个CPU有没有意义呢?

  也有很大的意义。如果不分块,相当于对100亿个数字遍历,作比较。这中间存在大量的没有必要的比较。可以举个例子说明,全校高一有100个班,我想找出全校前10名的同学,很傻的办法就是,把高一100个班的同学成绩都取出来,作比较,这个比较数据量太大了。应该很容易想到,班里的第11名,不可能是全校的前10名。也就是说,不是班里的前10名,就不可能是全校的前10名。因此,只需要把每个班里的前10取出来,作比较就行了,这样比较的数据量就大大地减少了。


      想法::先把数据平均分到1000个节点上,每个节点上1000w数据,先扫描一遍数据,找出数据的最大最小值,然后平均分成1w个区间, 再扫一遍数据,获得数据分布的直方图。然后从取值最大的区间开始往后扫,如果第一个区间里面已经有1000+的数据,则停止;否则继续扫下一个区间,直到找到1000+的数据。当然,如果有一个区间里面数据特别多,可以对这个区间进一步细分,计算出该区间的子直方图,使用同样的方法扫数据。最后输出的结果应该是所有数据加上最大和最小值。这个阶段就是map阶段。
这些数据汇聚起来之后,应该会剩下差不多十几或者几十万数据,可以单机计算了,也就是reduce阶段。对汇聚的数据进行处理时,可以先用最大最小值进行区间比较,提高效率。当然,也可以直接用最大堆算法进行处理。

另外,如果剩下的数据较多,比如说100w+,可以重复上面的map方法,只要保证分到每个节点上的数据大于1000就行。

如果需要多次map处理,最好用spark的流式处理,hadoop比较适合一次map-reduce的操作。

展开阅读全文

没有更多推荐了,返回首页