黑马程序员技术交流社区

标题: hadoop技术普及贴——Map、Reduce的本来面目是什么样子的? [打印本页]

作者: wuddd    时间: 2013-4-4 17:11
标题: hadoop技术普及贴——Map、Reduce的本来面目是什么样子的?
    在hadoop中最重要的就是基于hdfs的MapReduce分布式计算模型(以下简称“MR模型”)。hadoop周边的框架都是基于MapReduce做的各种操作,因此MapReduce是学好hadoop的基础。但是,很多初学者对Map、Reduce的本来面目不了解,一时之间不明白map、reduce到底是干什么的,为什么这个样子。下文试图逐一详解。

    Map、Reduce是两个函数,属于函数式编程语言中的固有函数。我们java属于面向对象语言,与函数式编程语言有很大区别。以下就以python为例讲述:

  
a=[1,2,3,4,5]
m = map(
lambda x:x+3, a)
list(m)
#[4, 5, 6, 7, 8]
  

    以上4条语句是用python写的。我现在逐一讲述每条语句。
    第一句是定义一个list,包含5个元素,赋值给一个变量a(python声明时不需要指定数据类型)。
    第二句是关键。其中蓝色的“lambda”是关键词,用于定义一个匿名函数。该匿名函数的形式参数是x,函数定义是返回x+3.那么“lambda x:x+3”就是定义一个匿名函数,形式参数是x,返回x+3。就这么简单。简单的理解为java中new一个接口就行了。好了,继续分析。这里的map就是一个函数。map函数包括两个参数,第一个就是刚才定义的匿名函数,第二个是一个a,即第一句中定义的list。map函数执行后,把返回值赋值给变量m。
    第三句是显示语句,使用list函数显示上面的运算结果m的值。
    第四句是显示第三句的运行结果。我们发现,map函数结果也是一个list,并且list中包含的元素个数与参数a的元素个数相同,但是m中的每个元素都是a中对应元素执行匿名函数的结果。
    以上就是python写的四句代码的全部含义。大家不要纠结python的语法,只需要关注map的含义即可。

  总结Mapper的含义是对输入的列表中的每一个元素执行一个函数,生成一个列表结果。运算前后列表的元素数量不变化

    我们在写MR模型时,覆盖Mapper类的map方法时,map函数的每个输入就是外部文件的每一行啊。这正是上面例子中map函数体现的要点。

    下面来看reduce函数的本来面目,还是以python代码为例:


import functools
a = [1,2,3,4,5]
s = functools.reduce(lambda x,y:x+y,a)
print(s)               
#15                                    
  

    以上一共包含5行python代码。
    第一行是导入类库。
    第二行是声明一个列表,包含5个元素,赋值给一个变量a。
    第三行是关键。首先看到一个匿名函数“lambda x,y:x+y”。该函数两个形式参数x和y。方法体是x+y。函数reduce的参数有两个,第一个是上面讲的匿名函数,第二个是列表a。运算后赋值给变量s。
    第四行是打印s。
    第五行是显示结果15.
    从以上例子可以看到,15是列表a执行匿名函数的结果。

    总结Reduce的含义就是“Reduce是对输入的列表中的所有元素执行一个函数操作,并将中间结果作为参数继续执行函数”。

    好像还是没理解吧?继续向下看Reduce的深度分析。

    Reduce中匿名函数的两个形参是x和y(假设默认值都是0),这个匿名函数在运行时传入的参数是a中的各个元素。其中x分别是1,2,3,4,5;那么y会传入什么值哪?y是x+y的累计值。

    一步步的遍历a中的元素,过程如下:
    1.x、y默认值都是 0
    2.当x=1,y=0时,运算完成后x+y,即1+0,等于1;
    3.当x=2,y=1时,运算完成后x+y,即2+1,等于3;
    4.当x=3,y=3时,运算完成后x+y,即3+3,等于6;
    5.当x=4,y=6时,运算完成后x+y,即4+6,等于10;
    6.当x=5,y=10时,运算完成后x+y,即5+10,等于15;

    可能会感觉到reduce的用法这么奇怪,因为python是函数式编程语言。函数语言中函数是一等公民,就像java中类一样普遍。

    python中的map、reduce函数会分别遍历参数a中的每一个元素,有点类似于java中的for循环,不必扣细节,大体理解就可以。举例子的目的就是为了让大家有个大致了解,方便以后的hadoop学习。

    同学们,理解map、reduce函数的本质了吗?不明白的,请留言吧

作者: ㄨ____陌生    时间: 2013-4-4 17:21
{:soso_e176:}{:soso_e176:}
作者: vmvm555    时间: 2013-4-4 17:25
沙发没抢到啊
作者: 邵天强    时间: 2013-4-4 17:27
顶一下老师,写的不错
作者: ying    时间: 2013-4-4 17:29
{:soso_e183:}
作者: 杨杨    时间: 2013-4-4 17:30
所为的函数 是不是跟类里面的方法一样啊

作者: wuddd    时间: 2013-4-4 17:31
本帖最后由 吴超老师 于 2013-4-4 17:33 编辑
杨杨 发表于 2013-4-4 17:30
所为的函数 是不是跟类里面的方法一样啊

简单地理解:是。

函数式语言python与面向对象语言java,设计思想是不一样的,开发思路也不一样。不要扣语法,重在理解。
作者: 黑马高明辉    时间: 2013-4-4 17:33
map函数是把原来的一组数重新建一个映射吗?
reduce函数是干嘛的,字面上是减少的意思,是说把映射的结果简化成一个值,相当于将前面那个map打包起来吗?
作者: 李芳池    时间: 2013-4-4 17:33
明白了哈,谢谢老师
总结两句
Mapper的含义是“对输入的列表中的每一个元素执行一个函数,生成一个列表结果。运算前后列表的元素数量不变化。”
Reduce的含义就是“Reduce是对输入的列表中的所有元素执行一个函数操作,并将中间结果作为参数继续执行函数”。

作者: 刘策    时间: 2013-4-4 17:33
老师那个map中的匿名函数中只可以有一个x形参吗,还可以有第二个吗,那lReduce中的匿名函数,可以只有一个形参吗,或多个形参呢,我比较对这个有点疑惑,这个是可以理解的,
作者: 王晓州    时间: 2013-4-4 17:36
学习了!:D
作者: wuddd    时间: 2013-4-4 17:39
刘策 发表于 2013-4-4 17:33
老师那个map中的匿名函数中只可以有一个x形参吗,还可以有第二个吗,那lReduce中的匿名函数,可以只有一个 ...

别扣语法细节,把文中红色加粗部分理解就行了。

map中的匿名函数只有一个形参。
reduce中的匿名函数只有两个形参。
作者: 刘策    时间: 2013-4-4 17:44
吴超老师 发表于 2013-4-4 17:39
别扣语法细节,把文中红色加粗部分理解就行了。

map中的匿名函数只有一个形参。

哦,明白。谢谢。
作者: wuddd    时间: 2013-4-4 17:45
黑马高明辉 发表于 2013-4-4 17:33
map函数是把原来的一组数重新建一个映射吗?
reduce函数是干嘛的,字面上是减少的意思,是说把映射的结果简 ...

简单的讲,你的理解是正确的。

函数的本质是映射。看一个函数的定义是什么,作用是什么,就是看函数的形参和返回值。如果纠结这个函数为什么起这个名字,那么学习方向就偏离轨道了。
作者: 杨杨    时间: 2013-4-4 17:47
reduce 跟java中的递归有点像啊
作者: wuddd    时间: 2013-4-4 17:50
杨杨 发表于 2013-4-4 17:47
reduce 跟java中的递归有点像啊

非常正确,赞一个:victory:
作者: 杨杨    时间: 2013-4-4 17:51
吴超老师 发表于 2013-4-4 17:50
非常正确,赞一个

老师 我想报云3期 看我 这潜质  能走个后门吗 呵呵 正在办理离职
作者: 黑马高明辉    时间: 2013-4-4 17:52
吴超老师 发表于 2013-4-4 17:45
简单的讲,你的理解是正确的。

函数的本质是映射。看一个函数的定义是什么,作用是什么,就是看函数的形 ...

恩,也是,不过函数名肯定也有一定的道理。
mapreduce是处理大数据的,我先感性地理解一下,这个是不是要把有的数据重新映射,然后有的数据打包处理。
reduce函数的意义也就是把一些数据相关地打包到一起,这样相当于减少了单个数据的映射数,类似于在检索大量数据的时候先能找到一个reduce的结果,然后在到这个结果里去找具体的哪个数据?

作者: wuddd    时间: 2013-4-4 18:05
本帖最后由 吴超老师 于 2013-4-4 18:07 编辑
黑马高明辉 发表于 2013-4-4 17:52
恩,也是,不过函数名肯定也有一定的道理。
mapreduce是处理大数据的,我先感性地理解一下,这个是不是要 ...

你说的“打包处理”,我不清楚什么意思。另外,你说的“映射数”,是不是我所说的“函数”,我也不确定。

mapreduce本质上是处理大数据的,没错。“处理大数据”就是我们平时对数据的“查重、计数、搜索”等。数据不大的话,这样的问题处理起来很简单。一旦数据量大了,处理就复杂了。原因见http://bbs.itheima.com/thread-44006-1-1.html。mapreduce只是处理大数据的一种模型,处理的思路是先map后reduce。鉴于map和reduce函数的特点,那么mapreduce不是适合于所有的大数据计算问题。只有一部分问题才能转化为mapreduce处理。说得太多了,呵呵

作者: wuddd    时间: 2013-4-4 18:09
杨杨 发表于 2013-4-4 17:51
老师 我想报云3期 看我 这潜质  能走个后门吗 呵呵 正在办理离职

我只负责讲课哦,报名事情还需要咨询具体老师。我可以肯定的是,黑马欢迎你,黑马适合你。

学习hadoop需要具有javaSE的知识,对jsp/servlet部分没有要求。
作者: 黑马高明辉    时间: 2013-4-4 18:22
吴超老师 发表于 2013-4-4 18:05
你说的“打包处理”,我不清楚什么意思。另外,你说的“映射数”,是不是我所说的“函数”,我也不确定。
...

呵呵,学习了,学习了,黑马的课程还是一如既往的好。
作者: 曹宇    时间: 2013-4-4 18:30
哈哈,谢谢分享啦!!!
作者: zjm10zj    时间: 2013-4-4 19:08
准备学,先备着
作者: 杨雪松    时间: 2013-4-4 19:09
顶一个:):D;P
作者: 蔡兆军    时间: 2013-4-4 19:36
老师,3天的课程学习到的知识,能去应聘hadoop方面的工作吗??
作者: wuddd    时间: 2013-4-4 19:42
本帖最后由 吴超老师 于 2013-4-4 19:45 编辑
蔡兆军 发表于 2013-4-4 19:36
老师,3天的课程学习到的知识,能去应聘hadoop方面的工作吗??

说个真实的例子,在传智最近刚毕业的一个学生,专门应聘hadoop职位,只会安装hadoop、hbase,收到了两份offer。一份是一家纳斯达克上市的互联网公司,一家是小公司,6.5K。他寻求更高的职位,目前还没入职。

更多的例子通过javaEE找到工作的。刚进入公司,就要求学习hadoop。这些的例子太多了,都发生在刚毕业的这几个班。

通过三天的学习,你绝不是仅仅安装hadoop、hbase的水平的。
作者: 冉世友    时间: 2013-4-4 19:58
老师讲得浅显易懂啊!
作者: 蔡兆军    时间: 2013-4-4 20:36
吴超老师 发表于 2013-4-4 19:42
说个真实的例子,在传智最近刚毕业的一个学生,专门应聘hadoop职位,只会安装hadoop、hbase,收到了两份of ...

老师你这么一说,我就有信心了。 现在才刚开始学习linux,为hadoop做准备。
作者: 王广智    时间: 2013-4-4 20:44
也就是mapper和reduce都是一个函数啊,执行的结果不同。
作者: wuddd    时间: 2013-4-4 20:55
王广智 发表于 2013-4-4 20:44
也就是mapper和reduce都是一个函数啊,执行的结果不同。

:funk:我哪段文字给你留下这个印象了,罪过啊

mapper和reducer是两个不同的函数。看入参就知道了。
作者: 杜鹏飞    时间: 2013-4-4 22:32
本帖最后由 杜鹏飞 于 2013-4-4 23:00 编辑

前几天看到同事买了一本书,讲的就是Hadoop,厚的吓死人,于是乎没怎么去了解。刚刚看到了老师的这篇文章,写的不错,百度了一下发现map和reduce似乎是
python固有的函数,而且reduce的兰博德表达式只支持传递两个参数,老师一开始没指明,害我苦思reduce的实现很久,这是后话了。本人未学习过python,故打算
用lua实现下这两个函数。map很简单:
  1. function map(f,list)
  2.         function list_table(list)
  3.                 local iter = 0
  4.                 local len = table.getn(list)
  5.                 return function()
  6.                         iter = iter+1
  7.                         if iter <= len then return list[iter] end
  8.                 end
  9.         end


  10.         local ret={}
  11.         for ele in list_table(list) do
  12.                 table.insert(ret,f(ele))
  13.         end
  14.         return ret
  15. end
复制代码
我采用了迭代器+泛型for的形式,python好像支持泛型for(函数式程序设计语言好像都支持T_T)
接下来写reduce,reduce的一般形式是容易实现的,但是,我忽然想到了一个东西,那就是如果让reduce去返回一个中间值的表,会如何呢?见程序:
  1. function reduce(f,list)
  2.         function list_table(list)
  3.                 local iter = 0
  4.                 local len = table.getn(list)
  5.                 return function()
  6.                         iter = iter+1
  7.                         if iter <= len then return list[iter] end
  8.                 end
  9.         end

  10.         local ret={}
  11.         for ele in list_table(list) do
  12.                 if table.getn(ret) == 0 --问题在此!
  13.                 then table.insert(ret,ele)
  14.                 else table.insert(ret,f(ret[table.getn(ret)],ele)) end
  15.         end
  16.         return ret
  17. end
复制代码
我的这种写法做了O(n)次无谓的判断!我认为应该有更优秀的写法,能深刻利用泛型for的特点或巧妙地赋值来避免无谓的测试,如能指点,不胜感激。
作者: 杜鹏飞    时间: 2013-4-4 23:18
额,智商拙计了,一直在想怎么用泛型for来实现这个特性,其实简单地记录一个变量就可以了。
  1. function reduce(f,list)
  2.         function list_table(list)
  3.                 local iter = 0
  4.                 local len = table.getn(list)
  5.                 return function()
  6.                         iter = iter+1
  7.                         if iter <= len then return list[iter] end
  8.                 end
  9.         end

  10.         local ret = {}
  11.         local sum = 0
  12.         for ele in list_table(list) do
  13.                 sum = f(sum,ele)
  14.                 table.insert(ret,sum)
  15.         end
  16.         return ret
  17. end
复制代码

作者: wuddd    时间: 2013-4-5 05:44
杜鹏飞 发表于 2013-4-4 22:32
前几天看到同事买了一本书,讲的就是Hadoop,厚的吓死人,于是乎没怎么去了解。刚刚看到了老师的这篇文章, ...

兄弟神勇,工作中一定是黑马一匹。

在python中增加map、reduce函数就是为了替代这种大段代码的。其他语言也能类似实现,代码越多,可维护越差。二者相较,优劣立显
作者: 杜鹏飞    时间: 2013-4-5 10:21
吴超老师 发表于 2013-4-5 05:44
兄弟神勇,工作中一定是黑马一匹。

在python中增加map、reduce函数就是为了替代这种大段代码的。其他语 ...

小生年逾弱冠,正打算这次去云三呢,还要多向老师请教!
作者: 王广智    时间: 2013-4-5 21:01
吴超老师 发表于 2013-4-4 20:55
我哪段文字给你留下这个印象了,罪过啊

mapper和reducer是两个不同的函数。看入参就知道了。 ...

我语言表述错误,老师,是他们都是函数,没有他们是一个函数的意思,看来以后语言应该注意防止二义性。
作者: 韩超    时间: 2013-4-7 16:38
没看懂哎郁闷
作者: wuddd    时间: 2013-4-7 23:12
王广智 发表于 2013-4-5 21:01
我语言表述错误,老师,是他们都是函数,没有他们是一个函数的意思,看来以后语言应该注意防止二义性。 ...

经过你这一解释,我忽然看懂了你表达的意思。哈哈。

我在写短信、qq聊天、写文章等的时候,每句话都斟酌多次,看是否理解有歧义,自己觉得有问题的时候删掉重写。这纯属自己习惯,和你无关啊,呵呵
作者: HM许涛    时间: 2013-4-23 00:08
过来学习科普知识
作者: 李志杰    时间: 2013-4-23 23:01
老师辛苦啦啊啊
作者: Miss小强    时间: 2013-4-29 18:36
可否这样理解:
int[] src={1,2,3,4,5};//五个元素
int[]result=new int[5];//和上面保持一致;
for(int i=0;i<src.length;i++){
result[i]=function(src[i]);
}对mapper的理解;
就是这两句话:列表中的每一个元素执行一个函数-----列表中的所有元素执行一个函数
这两句话有什么区别吗?





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2