MapReduce 的理解

1分钟理解map reduce,其实它就在我们身边http://heipark.iteye.com/blog/845267,就是:查找与汇总呗

linux平台下有个ls指令,大家都很熟悉:

① ls | grep 2008   查询文件名包含2008的文件(这其实就是一个map,找到需要的数据)

② ls | grep 2008 | wc -l 计算上述指令查询文件个数(这其实就是一个reduce,对找到数据进行汇总聚合)

 

再来一个例子,关于SQL:select * from device

 

① select * from device t where t.name like 'CNC-Bj%'  (这其实就是一个map,找到需要的数据)

② select count(*) from device t where t.name like 'CNC-Bj%' (这其实就是一个reduce,对找到数据进行汇总聚合)

 

第二个SQL的例子在hive中就是通过mapreduce实现的,①为一个map任务 ②为一个reduce任务


再来看看那我们神奇的度娘是怎解析的呗

感觉这个也比较好理解,简单理解:主要是map:键值对<K,V>,--------->Combiner (对本地相同的K合并,类似reduce的作用)------>reduce<K,List<V>>reduce是组合的values,,

统计词频的例子

   [2] 如果想统计下过去10年计算机论文出现最多的几个单词,看看大家都在研究些什么,那收集好论文后,该怎么办呢?
  方法一:我可以写一个小程序,把所有论文按顺序遍历一遍,统计每一个遇到的单词的出现次数,最后就可以知道哪几个单词最热门了。
  这种方法在数据集比较小时,是非常有效的,而且实现最简单,用来解决这个问题很合适。
  方法二:写一个多线程程序,并发遍历论文。
  这个问题理论上是可以高度并发的,因为统计一个文件时不会影响统计另一个文件。当我们的机器是多核或者多处理器,方法二肯定比方法一高效。但是写一个多线程程序要比方法一困难多了,我们必须自己同步共享数据,比如要防止两个线程重复统计文件。
  方法三:把作业交给多个计算机去完成。
  我们可以使用方法一的程序,部署到N台机器上去,然后把论文集分成N份,一台机器跑一个作业。这个方法跑得足够快,但是部署起来很麻烦,我们要人工把程序copy到别的机器,要人工把论文集分开,最痛苦的是还要把N个运行结果进行整合(当然我们也可以再写一个程序)。
  方法四:让MapReduce来帮帮我们吧!
  MapReduce本质上就是方法三,但是如何拆分文件集,如何copy程序,如何整合结果这些都是框架定义好的。我们只要定义好这个任务( 用户程序 ),其它都交给MapReduce。

map函数和reduce函数

  map函数和reduce函数是交给用户实现的,这两个函数定义了任务本身。
  map函数:接受一个键值对(key-value pair),产生一组中间键值对。MapReduce框架会将map函数产生的中间键值对里键相同的值传递给一个reduce函数。
  reduce函数:接受一个键,以及相关的一组值,将这组值进行合并产生一组规模更小的值(通常只有一个或零个值)。
  统计词频的MapReduce函数的核心代码非常简短,主要就是实现这两个函数。
  map(String key, String value):
  // key: document name
  // value: document contents
  for each word w in value:
  EmitIntermediate(w, "1");
  reduce(String key, Iterator values):
  // key: a word
  // values: a list of counts
  int result = 0;
  for each v in values:
  result += ParseInt(v);
  Emit(AsString(result));
  在统计词频的例子里,map函数接受的键是文件名,值是文件的内容,map逐个遍历单词,每遇到一个单词w,就产生一个中间键值对<w, "1">,这表示单词w咱又找到了一个;MapReduce将键相同(都是单词w)的键值对传给reduce函数,这样reduce函数接受的键就是单词w,值是一串"1"(最基本的实现是这样,但可以优化),个数等于键为w的键值对的个数,然后将这些“1”累加就得到单词w的出现次数。最后这些单词的出现次数会被写到用户定义的位置,存储在底层的 分布式存储系统 (GFS或HDFS)。

工作原理

  
MapReduce执行流程

  MapReduce执行流程

  上图是论文里给出的流程图。一切都是从最上方的user program开始的,user program链接了MapReduce库,实现了最基本的Map函数和Reduce函数。图中执行的顺序都用数字标记了。
  1.MapReduce库先把user program的输入文件划分为M份(M为用户定义),每一份通常有16MB到64MB,如图左方所示分成了split0~4;然后使用fork将用户进程拷贝到集群内其它机器上。
  2.user program的副本中有一个称为master,其余称为worker,master是负责调度的,为空闲worker分配作业(Map作业或者Reduce作业),worker的数量也是可以由用户指定的。
  3.被分配了Map作业的worker,开始读取对应分片的输入数据,Map作业数量是由M决定的,和split一一对应;Map作业从输入数据中抽取出键值对,每一个键值对都作为 参数传递 给map函数,map函数产生的中间键值对被 缓存 在内存中。
  4.缓存的中间键值对会被定期写入 本地磁盘 ,而且被分为R个区,R的大小是由用户定义的,将来每个区会对应一个Reduce作业;这些中间键值对的位置会被通报给master,master负责将信息转发给Reduce worker。
  5.master通知分配了Reduce作业的worker它负责的分区在什么位置(肯定不止一个地方,每个Map作业产生的中间键值对都可能映射到所有R个不同分区),当Reduce worker把所有它负责的中间键值对都读过来后,先对它们进行排序,使得相同键的键值对聚集在一起。因为不同的键可能会映射到同一个分区也就是同一个Reduce作业(谁让分区少呢),所以排序是必须的。
  6.reduce worker遍历排序后的中间键值对,对于每个唯一的键,都将键与关联的值传递给reduce函数,reduce函数产生的输出会添加到这个分区的输出文件中。
  7.当所有的Map和Reduce作业都完成了,master唤醒正版的user program,MapReduce 函数调用 返回user program的代码。
  所有执行完毕后,MapReduce输出放在了R个分区的输出文件中(分别对应一个Reduce作业)。用户通常并不需要合并这R个文件,而是将其作为输入交给另一个MapReduce程序处理。整个过程中,输入数据是来自底层 分布式文件系统 (GFS)的,中间数据是放在本地文件系统的,最终输出数据是写入底层分布式文件系统(GFS)的。而且我们要注意Map/Reduce作业和map/reduce函数的区别:Map作业处理一个输入数据的分片,可能需要调用多次map函数来处理每个输入键值对;Reduce作业处理一个分区的中间键值对,期间要对每个不同的键调用一次reduce函数,Reduce作业最终也对应一个输出文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值