统计一个至关大的数据文件中,每一个单词出现的个数。html
map:java
reduce:linux
对从map中获得的数据的valuelist遍历累加,获得一个单词的总次数apache
重写Mapper类的map方法。windows
mapreduce框架每读一行数据就调用一次该方法,map的具体业务逻辑就写在这个方法体中。缓存
package cn.thousfeet.hadoop.mapreduce.wordcount; import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class WordCountMapper extends Mapper<LongWritable, Text, Text, LongWritable>{ @Override protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, LongWritable>.Context context) throws IOException, InterruptedException { String line = value.toString(); String[] words = StringUtils.split(line," "); //切分单词 for(String word : words) //遍历 输出为key-value( <word,1> ) { context.write(new Text(word), new LongWritable(1)); } } }
重写Reducer类的reduce方法。网络
框架在map处理完成后,将全部的key-value对缓存起来进行分组,而后传递到一个组 <key,values{}>
(对于wordcount程序,拿到的就是相似<hello,{1,1,1,1...}>
),而后调用一次reduce方法。app
package cn.thousfeet.hadoop.mapreduce.wordcount; import java.io.IOException; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class WordCountReducer extends Reducer<Text, LongWritable, Text, LongWritable>{ @Override protected void reduce(Text key, Iterable<LongWritable> valueList, Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException { long count = 0; for(LongWritable value : valueList) //遍历value list累加求和 { count += value.get(); } context.write(key, new LongWritable(count)); //输出这一个单词的统计结果 } }
用于描述job。框架
好比,该做业使用哪一个类做为逻辑处理中的map,哪一个做为reduce。还能够指定该做业要处理的数据所在的路径,和输出的结果放到哪一个路径。eclipse
package cn.thousfeet.hadoop.mapreduce.wordcount; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; public class WordCountRunner { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf); //设置整个job所用的那些类在哪一个jar包 job.setJarByClass(WordCountRunner.class); //指定job使用的mapper和reducer类 job.setMapperClass(WordCountMapper.class); job.setReducerClass(WordCountReducer.class); //指定reduce和mapper的输出数据key-value类型 job.setOutputKeyClass(Text.class); job.setMapOutputValueClass(LongWritable.class); //指定mapper的输出数据key-value类型 job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(LongWritable.class); //指定原始输入数据的存放路径 FileInputFormat.setInputPaths(job, new Path("/wordcount/srcdata/")); //指定处理结果数据的存放路径 FileOutputFormat.setOutputPath(job, new Path("/wordcount/output/")); //将job提交给集群运行 参数为true时会打印运行进度 job.waitForCompletion(true); } }
export成一个jar包,上传到虚拟机上。
分发到集群运行:hadoop jar wordcount.jar cn.thousfeet.hadoop.mapreduce.wordcount.WordCountRunner
查看输出结果:
(能够看到按key的字典序升序排序)
首先,由于要在windows下直接调试,须要在eclipse的设置 Run Configurations->arguments->vm arguments ,添加
-DHADOOP_USER_NAME=对应用户
。
如需在本地直接run main方法(MapReduce程序在本机的JVM运行),要把输入输出路径改成hdfs全路径或把site.xml配置文件拖进来(或用在windows本地目录下的数据也行,MapReduce程序的运行和数据来源在哪无关)。
如需实如今本地run main方法而MapReduce实际运行在集群(这种方式必须在linux下),应:
mapreduce.framework.name
和yarn.resourcemanager.hostname
等参数)conf.set("mapreduce.job.jar","wordcount.jar");
(在windows下要用这种方法须要修改hadoop的YarnRunner这个类的源码,或者安装插件什么的..)
提交到yarn集群的job能够在yarn的管理页面(8088端口)看到。
yarn只负责资源的分配,而后启动运算框架的主管进程AppMaster(如运算框架是MapReduce时主管进程就是它的MRAppMaster),剩下的工做就不禁yarn去作了。
MapReduce只适合作数据的批量离线处理,而不适用于实时性的需求,要实现实时性要使用的运算框架是spark、storm那些,但均可以放在yarn框架下。yarn和运算框架分离的策略使得hadoop具备普遍的实用性和生命力。
运行程序后查看output文件夹能看到运行成功了,可是cat查看part-r-00000的时候报错
error creating legacy BlockReaderLocal. Disabling legacy local reads.
org.apache.hadoop.security.AccessControlException: Can't continue with getBlockLocalPathInfo() authorization. The user thousfeet is not configured in dfs.block.local-path-access.user
解决方法是hdfs-site.xml中的配置项dfs.client.read.shortcircuit=false
woc,这个参数其实本来默认就是false...忽然想起这不是上次配置出错的时候病急乱投医加上的吗,果真乱跟教程害死人orzz
(参考:http://www.51testing.com/html/59/445759-821244.html)