探秘Hadoop生态3:MapReduce简介与WordCount

No.10 MapReduce 编程模型极简篇

dantezhao 木东居士 2017-09-23

0x00 前言

回想自己最初学 Hadoop 的时候,初衷是写MapReduce程序,但是搭建单机环境折腾一周,搭建分布式环境折腾一周,跑个Demo解决一下Bug又一周过去了。最后都忘了自己是想学 MapReduce 的。

感觉自己虽然是搞Hadoop的,但是写MR比自己想的要少很多。初期是花了很多精力在安装以及集群的各种日常维护,熟悉Hive后就经常用Hive来解决问题,然后逐渐地各种任务过度到了Spark上,因此对MapReduce的重视就少了很多。 细想起来,MapReduce本身是很简洁易学的,因此这次抛开各种MapReduce背后的实现原理,来专门回顾一下它的编程模型。

0x01 编程模型

MapReduce计算提供了简洁的编程接口,对于某个计算任务来说,其输入是Key/Value数据对,输出也以Key/Value数据对方式表示。

对于应用开发者来说,只需要根据业务逻辑实现Map和Reduce两个接口函数内的具体操作内容,即可完成大规模数据的并行批处理任务。

Map 函数以Key/Value数据对作为输入,将输入数据经过业务逻辑计算产生若干仍旧以Key/Value形式表达的中间数据。MapReduce计算框架会自动将中间结果中具有相同Key值的记录聚合在一起,并将数据传送给Reduce函数内定义好的处理逻辑作为其输入值。

Reduce 函数接收到Map阶段传过来的某个Key值及其对应的若干Value值等中间数据,函数逻辑对这个Key对应的Value内容进行处理,一般是对其进行累加、过滤、转换等操作,生成Key/Value形式的结果,这就是最终的业务计算结果。

0x02 举个栗子

1. 问题描述

举个MapReduce最经典的例子——WordCount。假设给你100亿的文本内容,如何统计每个单词的总共出现次数?或者说统计出统计出现次数最多的N个单词?

这个任务看似简单,但如果在单机环境下快速完成还是需要实现技巧的,主要原因在于数据规模巨大。在MapReduce框架中实现的话就会简单很多,只要实现相应的和Map和Reduce函数即可。

2. 代码实现

我们用Python实现一下大致的逻辑:

def map(key, value):    values = value.split(" ")    for v in values:        print (v, "1")def reduce(key, value):    int result=0    for v in value:        result += int(v)    print (key, result)

Map操作的key是一个文件的ID或者一个网页的ID,value是它的正文内容,即由一系列单词组成。Map函数的主要作用是把文本内容解析成一个个单词和单词出现的次数,比如<w,1>。一般我们不太关注Map中的key,只解析其中的value即可。

Reduce操作的key值为某个单词,对应的Value为出现次数列表,通过遍历相同Key的次数列表并累加其出现次数,即可获得某个单词在网页集合中总共出现的次数。

3. 分析

画个整体的图,来解释一下MapReduce的过程都做了什么。

  1. 最左边是我们需要统计的文本内容,假设我们现在与三个问题,每个里面都有一些内容。
  2. Map阶段会有我们的Map函数来读取相应的文本,并解析出其中的单词,然后输出dantezhao 1这种结构,其中key是dantezhao,value是出现次数1。
  3. 然后这里会经过一个Shuffle过程,把相同key的数据放到同一个Reduce中来处理,比如我们这里会把所有key为dantezhao的数据发送到第二个Reduce中。
  4. Reduce阶段,根据相同的key,计算出它出现的次数,即将value值相加。

0xFF 总结

单纯的MapReduce编程模型其实还是不难的,当然想深入学还是有很多细节的,比如Partitioner的设计、Shuffle阶段的设计,Map和Reduce的一些优化。这里暂且做一个最基本的回顾。

 

 

Hadoop的“Hello world”---WordCount

2016-02-14

薛彬

 Hadoop

 Hadoop  MapReduce  Wordcount


在安装并配置好Hadoop环境之后,需要运行一个实例来验证配置是否正确,Hadoop就提供了一个简单的wordcount程序,其实就是统计单词个数的程序,这个程序可以算是Hadoop中的“Hello World”了。

MapReduce

原理

MapReduce其实就是采用分而治之的思想,将大规模的数据分成各个节点共同完成,然后再整合各个节点的结果,得到最终的结果。这些分节点处理数据都可以做到并行处理,大大缩减了工作的复杂度。

过程

MapReduce可以分成两个阶段,其实就是单词拆成map和reduce,这其实是两个函数。map函数会产生一个中间输出,然后reduce函数接受多个map函数产生的一系列中间输出然后再产生一个最终输出。

WordCount展示

前期工作

启动hadoop

cd /usr/hadoop/hadoop-2.6.2/sbin/start-dfs.shsbin/start-yarn.sh

创建本地数据文件

cd ~/mkdir ~/filecd fileecho "Hello World" > test1.txtecho "Hello Hadoop" > test2.txt

这样就创建了两个txt文件,里面分别有一个字符串:Hello World,Hello Hadoop。我们通过wordcount想要得到的结果是这样的:Hello 2,World 1,Hadoop 1。

在HDFS上创建输入文件夹

hadoop fs -mkdir /input

创建好我们可以通过

hadoop fs -ls /

来查看结果:

将数据文件传到input目录下

hadoop fs -put ~/file/test*.txt /input

同样,我们可以通过

hadoop fs -ls /input

来查看是否上传成功:

如果看不到任何结果,说明在hadoop的配置中存在问题,或者是防火墙没有关闭,导致节点连接不通。

运行程序

运行wordcount

hadoop jar /你的hadoop根目录/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.2.jar wordcount /input /output

运行这条命令后,Hadoop会启动一个JVM来运行MapReduce程序,而且会在集群上创建一个output文件夹,将结果存在其中。

我们来看看结果:

注意点:

  • 这个目录一定要填对,要不然会报jar不存在。
  • 输出文件夹一定要是空文件夹。

查看结果

output文件夹中现在有两个文件,我们需要的结果在part-r-00000这个文件夹中。

hadoop fs -cat /output/part-r-00000

我们就可以看到最终的wordcount结果了:

WordCount源码分析

Map过程

源码:

import java.io.IOException;import java.util.StringTokenizer;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Mapper;public class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {IntWritable one = new IntWritable(1);Text word = new Text();public void map(Object key, Text value, Context context) throws IOException,InterruptedException {StringTokenizer itr = new StringTokenizer(value.toString());while(itr.hasMoreTokens()) {word.set(itr.nextToken());context.write(word, one);}}}

继承Mapper类,重写map方法。

我们了解到mapreduce中数据都是通过<key,value>传递的。我们可以通过控制台来看看其中的value值和key值是什么样的。在map方法中加入以下代码:

System.out.println("key= "+key.toString());//查看key值System.out.println("value= "+value.toString());//查看value值

运行程序后控制台输出如下:

我们可以看出,map方法中的value值存储的是文本文件中的一行,而key值为该行的首字符相对于文本文件的首地址的偏移量。

程序中的StringTokenizer这个类的功能是将每一行拆分成一个一个的单词,并将<word,1>作为map方法的结果输出。

Reduce过程

源码:

import java.io.IOException;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Reducer;public class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {IntWritable result = new IntWritable();public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException,InterruptedException {int sum = 0;for(IntWritable val:values) {sum += val.get();}result.set(sum);context.write(key,result);}}

同样,Reduce过程也需要继承一个Reducer类,并重写reduce方法。

我们可以看到reduce的输入参数是Text keyIterable<Intrable>。我们知道reduce方法的输入参数key是一个单词,而values是由各个Mapper上对应单词的计数值所组成的列表,我们可以看到values实现了一个Iterable接口,可以理解成values里面包含了多个IntWritable整数,其实也就是计数值。

然后我们只要遍历values并且求和,就可以得到各单词的总次数了。

执行MapReduce

我们已经写好了map函数和reduce函数,现在就是要执行mapreduce了。

源码:

import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Job;import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import org.apache.hadoop.util.GenericOptionsParser;public class WordCount {public static void main(String[] args) throws Exception {Configuration conf = new Configuration();String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();if(otherArgs.length != 2) {System.err.println("Usage: wordcount <in> <out>");System.exit(2);}Job job = new Job(conf, "wordcount");job.setJarByClass(WordCount.class);job.setMapperClass(TokenizerMapper.class);job.setCombinerClass(IntSumReducer.class);job.setReducerClass(IntSumReducer.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);FileInputFormat.addInputPath(job, new Path(otherArgs[0]));FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));System.exit(job.waitForCompletion(true)?0:1);} }

代码中的job.set*()方法是为对任务的参数进行相关的设置,然后调用job.waitForCompletion()方法执行任务。

微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点Docker、ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!

全部评论

相关推荐

2025-12-27 16:21
已编辑
门头沟学院 Java
bg:中下211本科,java后端,无竞赛,无基础,大一升大二暑假开始学java。五段实习:美团-小红书-腾讯-淘天-字节。面秋招的简历只有美团、小红书、淘天。刚刚发现我的秋招蚂蚁流程挂了,这是我最后一个流程,那么我的秋招就算彻底结束了,总结一下:字节ssp+,职级2-1。美团ssp,+2打了半小时微信电话极力挽留。快手ssp,但报了字节薪资后没有争取的想法了。小红书sp,今年小红书给的很高,但比字节2-1还是差很多。虾皮应该是小sp?对虾皮一点意向都没,纯拿来集邮了。淘天ssp(暑期转正),说不要我的三方,毕业前考虑好了随时可以不签三方选择淘天。挂了的流程:京东二面挂,估计学历被卡了。懂车帝一面挂,和面试官聊不来,不认同我的方案。拼多多hr面挂,问我低于预期还来不来,当时说不考虑了,估计觉得我不忠诚。蚂蚁hr面挂,聊的还行,但估计我不会去给我挂了吧。阿里控股一面挂,没面前就知道是kpi了,因为时间可选的很多,而且都是半小时,我也拿他刷我的kpi了。上面差不多是我的情况,下面是我想说的话。我觉得我不算特别突出优秀的那类人,但我多少也算是靠前的那一批人,即使这样,秋招也不算特别顺利,也有挂了的流程,但你能说是我的问题吗,我觉得大部分情况不是的,如果真的是我的问题,我不可能本科校招拿到2-1,所以很多面试挂了,问题不出在面试者身上,很多是看运气+眼缘+和面试官合不合得来。所以我觉得,学会察言观色,了解面试官的脾性,也是面试很重要的一个点。比如面试官是喜欢听长回答,还是听短回答,他更看重哪些点,每个面试官对这些的侧重都是不一样的,所以作为面试者,要学会察言观色,通过面试官开局的一两个问题以及你回答后他的表现,就要判断出来。像我现在其实面试开局个五分钟,我就基本能判断个七七八八了,然后我后面的回答就会有所变化。这是我想说的第一个点:不要为面试结果焦虑,有时候问题不出在你身上,但你可以学一些面试技巧,尽量提高你的面试通过率,这里说的面试技巧指的不是网上那种烂大街的,一两分钟短视频说什么提高你面试通过率的,而是你要在你自己的面试过程中不断总结经验,吸取教训,旁人教你的终究是有限的。另外想说下选offer的事,上面其实可以看出来,我秋招最后是选了字节的,还没签三方我就来提前实习感受业务了,当我签完三方又过了一个多月,我这些天又在想这个问题,字节真的是我想要的吗,我现在总结了一下字节的好坏,发现当时可能被字节的高薪资影响判断了,如果现在再选一次的话,我应该会选杭州的小红书,会生活的更舒服点。具体种种就不展开说了。然后虽然我现在也可以说去把小红书舔回来,去毁字节,但我觉得没必要这么做,我可以采用其他的措施去不就,比如规划好两年内就跳槽,跳到杭州,跳到更舒适的城市。我觉得大家选offer的时候,真的可以冷静下来多方面考虑,薪资、城市、组内氛围、业务、老板是否看重、组内情况、未来升职机会等等都是可以考虑的因素,虽然有的时候不管选哪个,都不会坏,但最好也别让自己后悔吧,即使真后悔了,我觉得也没必要过度美化没走过的路,想好补救措施即可。这是我想说的第二个点:冷静好好做选择,不管是offer还是其他。但人生容错率很大,即使选错了,也一定有补救措施。最后还想说一些成长上的东西,尤其是现在AI火热的时代。我觉得大家如果想提高自己,或者说在未来社招跳槽有竞争力,肯定是要学AI相关的东西的,不说要会多懂AI,至少也要了解基本概念,而且一定要学会用AI提效。我现在字节的mt和我说,他现在80%代码都是AI写的。而我最近也开始尝试用AI工具,感觉现在AI真的进步很多,挺聪明的了,我现在写需求基本都是先让AI写,我再人工review小改动一下就差不多了。我觉得「AI取代程序员」是个很远的话题,但是「AI取代不会用AI的程序员」,可能真的就是近两年的事了。而怎么去学习这块的内容,其实我也正在探索,我也是刚学AI的起步阶段,我觉得大家也要有自己的信息检索能力,而不是别人喂你什么,你才学什么,自己一个人就不会学了。这是我想说的第三个点:趁年轻,多学习提升自己,拥抱AI,不要原地踏步,原地踏步的程序员最容易被淘汰。大概就是这样吧,今天看蚂蚁流程发现挂了,前几天腾讯约面我也拒了,就想到自己的秋招/校招算彻底结束了,有感而发,随便聊了下。牛客以后应该不会更新,大家不用关注,熟悉我的朋友应该知道我在其他平台有号。我更喜欢以长视频的形式去做分享,感觉会更有体系,而不是网上那种一两分钟的零碎短视频的那种营销号去起号,我也推荐大家多去看高质量的长文章、长视频,我觉得收获的能更多。希望大家能收获满意的offer与未来。
CEXBB:刷到最后才发现原来是优雅✌🏻,我的Java引路人
2025年终总结
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务