Hadoop学习笔记2 - 第一和第二个Map Reduce程序
转载请标注原链接http://www.cnblogs.com/xczyd/p/8608906.html
在Hdfs学习笔记1 - 使用Java API访问远程hdfs集群中,我们已经可以完成了访问hdfs的配置。
接下来我们试图写一个最简单的map reduce程序。网上一般给的Demo都是统计词频(Word Count),
于是我们也简单先实现一下:
首先准备一个内容大致如下的test.txt文件:
aa
bbb
aaa
ab
ba
bb
bbb
bba
baa
aa
aaa
aa
aab
每行有且仅有一个单词,然后我们的程序需要完成的任务是统计每个词出现的次数。代码如下:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; import java.io.*;
import java.util.StringTokenizer; public class MRTest { public static class WordCountMap extends Mapper<Object, Text, Text, IntWritable> { private Text word = new Text();
private final static IntWritable one = new IntWritable(1); //key: 行号//value: 单词
@Override
protected void map(Object key, Text value, Context context) throws IOException,
InterruptedException {
StringTokenizer tokenizer = new StringTokenizer(value.toString());
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
word.set(token);
context.write(word, one);
}
}
} public static class WordCountReduce extends Reducer<Text, IntWritable, Text,
IntWritable> { private IntWritable result = new IntWritable(); //key: 单词
//values: 在map阶段写入的one的数量
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value: values) {
sum += value.get();
}
result.set(sum);
context.write(key, result);
}
} public static void main(String[] args) throws IOException, ClassNotFoundException,
InterruptedException { System.setProperty("HADOOP_USER_NAME", "root"); String hdfsUserName = "root";
String inputPath = "/jzhang4/test2.txt";
String outputPath = "/jzhang4/out"; Configuration conf = new Configuration(); conf.set("fs.default.name", "hdfs://hd-nn-test-01:9000");
conf.set("dfs.client.use.datanode.hostname","true"); FileSystem fs = FileSystem.get(conf);
fs.delete(new Path(outputPath), true); Job job = Job.getInstance(conf); job.setJarByClass(MRTest.class);
job.setJobName("jzhang4_avg_calc"); job.setMapperClass(WordCountMap.class);
job.setReducerClass(WordCountReduce.class);
TextInputFormat.setInputPaths(job, new Path(inputPath));
TextOutputFormat.setOutputPath(job, new Path(outputPath));
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); while (true) {
if (job.waitForCompletion(true)) {
break;
} else {
Thread.sleep(1000);
}
}
}
}
首先在map阶段,我们每读到一个word,就往context里面对应的word上添加一个1;
然后再reduce阶段,对于每一个word,再把这些1给累加起来;
main函数中有一些对于job的配置,主要是为了在IDE中运行此map reduce程序,
如果想要打成jar包放到服务器上去运行,或者是想在yarn上执行,需要调整配置,这些内容不在本篇讨论范围之内。
马不停蹄(事实上停了一天|||- -),立刻开始第二个Map Reduce程序。给定如下这么一个文件:
10
9
8
7
6
5
4
3
2
1
0
每行有且仅有一个数字。写一个map reduce程序来计算所有数字的平均值。
第一反应当然是照抄一下上面的程序,只是在map阶段往context里写入要统计的数字本身,
然后reduce阶段把这些数字加和再除以数字的数目即可。
但是老板说,这么操作过于naive。于是想到了map reduce中的计数器(Recorders),利用计数器可以
在reduce阶段什么也不做就得到均值。于是代码如下:
public static class CalculateAvgMap extends Mapper<Object, Text, Text,
IntWritable> { private final static IntWritable one = new IntWritable(1); public enum Recorders {
ItemCounter,
ValueCounter
} //key: 行号
//value: 数字
@Override
protected void map(Object key, Text value, Context context) throws IOException,
InterruptedException {
StringTokenizer tokenizer = new StringTokenizer(value.toString());
while (tokenizer.hasMoreTokens()) {
int number = Integer.parseInt(tokenizer.nextToken());
context.getCounter(Recorders.ItemCounter).increment(1);
context.getCounter(Recorders.ValueCounter).increment(number);
}
}
} public static class CalculateAvgReduce extends Reducer<Text, IntWritable, Text,
IntWritable> { private DoubleWritable result = new DoubleWritable(); @Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
}
}
然后在适当的地方(比如main函数中)获得计数器的值即可:
public static void main(String[] args) throws IOException, ClassNotFoundException,
InterruptedException { System.setProperty("HADOOP_USER_NAME", "root"); String hdfsUserName = "root";
String inputPath = "/jzhang4/test2.txt";
String outputPath = "/jzhang4/out"; Configuration conf = new Configuration(); conf.set("fs.default.name", "hdfs://hd-nn-test-01:9000");
conf.set("dfs.client.use.datanode.hostname","true"); FileSystem fs = FileSystem.get(conf);
fs.delete(new Path(outputPath), true); Job job = Job.getInstance(conf); job.setJarByClass(MRTest.class);
job.setJobName("jzhang4_avg_calc"); job.setMapperClass(CalculateAvgMap.class);
job.setReducerClass(CalculateAvgReduce.class);
TextInputFormat.setInputPaths(job, new Path(inputPath));
TextOutputFormat.setOutputPath(job, new Path(outputPath));
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
while (true) {
if (job.waitForCompletion(true)) {
break;
} else {
Thread.sleep(1000);
}
} Counters counters = job.getCounters(); Counter itemCounter = counters.findCounter(
CalculateAvgMap.Recorders.ItemCounter);
System.out.println(itemCounter.getName() + "\t" + itemCounter.getValue());
Counter valueCounter = counters.findCounter(
CalculateAvgMap.Recorders.ValueCounter);
System.out.println(valueCounter.getName() + "\t" + valueCounter.getValue());
}
这个实现有一定的问题,就是加合的结果会存在超界的风险。如果想要避免超界,比较合适的做法是利用bitmap的思想,
开32个或者64个Recorder,分别记录每一个bit的count数。当然在enum里面写茫茫多Recorder有点蠢,
在找到更优雅的办法之前,暂时先不写这么丑陋的代码了...
Hadoop学习笔记2 - 第一和第二个Map Reduce程序的更多相关文章
- progit 学习笔记-- 1 第一章 第二章
* 1 起步** 关于版本控制*** 什么是版本控制?记录文件变化,查阅特定版本,回溯到之前的状态.任何类型的文件进行版本控制.复制整个目录 加上备份时间 简单 混淆 无法恢复本地版本控制 数据库记 ...
- Python学习笔记系列——高阶函数(map/reduce)
一.map #变量可以指向函数,函数的参数能接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数被称之为高阶函数 def add(x,y,f): return f(x)+f(y) print( ...
- Hadoop学习笔记(10) ——搭建源码学习环境
Hadoop学习笔记(10) ——搭建源码学习环境 上一章中,我们对整个hadoop的目录及源码目录有了一个初步的了解,接下来计划深入学习一下这头神象作品了.但是看代码用什么,难不成gedit?,单步 ...
- Hadoop学习笔记(9) ——源码初窥
Hadoop学习笔记(9) ——源码初窥 之前我们把Hadoop算是入了门,下载的源码,写了HelloWorld,简要分析了其编程要点,然后也编了个较复杂的示例.接下来其实就有两条路可走了,一条是继续 ...
- Stealth视频教程学习笔记(第一章)
Stealth视频教程学习笔记(第一章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
- Hadoop学习笔记(5) ——编写HelloWorld(2)
Hadoop学习笔记(5) ——编写HelloWorld(2) 前面我们写了一个Hadoop程序,并让它跑起来了.但想想不对啊,Hadoop不是有两块功能么,DFS和MapReduce.没错,上一节我 ...
- Hadoop学习笔记(3)——分布式环境搭建
Hadoop学习笔记(3) ——分布式环境搭建 前面,我们已经在单机上把Hadoop运行起来了,但我们知道Hadoop支持分布式的,而它的优点就是在分布上突出的,所以我们得搭个环境模拟一下. 在这里, ...
- Hadoop学习笔记(4) ——搭建开发环境及编写Hello World
Hadoop学习笔记(4) ——搭建开发环境及编写Hello World 整个Hadoop是基于Java开发的,所以要开发Hadoop相应的程序就得用JAVA.在linux下开发JAVA还数eclip ...
- Hadoop学习笔记之HBase Shell语法练习
Hadoop学习笔记之HBase Shell语法练习 作者:hugengyong 下面我们看看HBase Shell的一些基本操作命令,我列出了几个常用的HBase Shell命令,如下: 名称 命令 ...
随机推荐
- Introduction and use of Cookie and Session(Cookie&Session的介绍和使用)
一.Cookie 1.什么是Cookie? Cookie是HTTP协议的规范之一,它是服务器和客户端之间传输的小数据. 首先由服务器通过响应头把Cookie传输给客户端,客户端会将Cookie保存起来 ...
- Gulp 之图片压缩合并
同事需要处理很多的图片,由于UI那边提供图片比较大,为了性能好一点,程序包小一点,因此希望我帮忙做成小程序来完成此工作. 其实之前做过一个grunt写的图片压缩合并工具,当时是为了处理270多个国家/ ...
- 基于DES加密的服务端分析
此程序建立了一个TCP服务端,端口号为10010,之后accept等待连接,如果接受到连接,那么就发送一些欢迎信息,以及提示信息---发送quit退出. 之后不停地调用recv,如果接受到数据,那么判 ...
- python 网络编程(Socket)
# from wsgiref.simple_server import make_server## def RunServer(environ,start_response):# start_resp ...
- 假如有Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小
假如有Thread1.Thread2.Thread3.Thread4四条线程分别统计C.D.E.F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现? 实现1:用concur ...
- 如何推进企业流程体系建设?_K2 BPM
推进全集团统一的流程体系为什么比想象的难? 很多企业在推进全集团的流程管理过程中,经常会有一种“望山跑死马”的感觉.“各成员公司都建立起与集团公司统一的流程管理体系”,看似很简单一件事情,但没有经过良 ...
- java类的理解和相关问题
---java抽象类 当我们定义的对象无法抽象或者不适合抽象为一个具体的类的时候 我们通常定义其为一个抽象类 like 衣服 (多种衣服) 手机 (多种手机) ---接口和抽象类的异同 对于概念上来说 ...
- datatable 添加列之前判断是否存在该列
if (!dt.Columns.Contains("BDate")) { DataColumn dc1 = new DataColumn("BDate", ty ...
- MySQL MERGE存储引擎
写这篇文章,主要是因为面试的时候,面试官问我怎样统计所有的分表(假设按天分表)数据,我说了两种方案,第一种是最笨的方法,就是循环查询所有表数据(肯定不能采用):第二种方法是,利用中间件,每天定时把前一 ...
- 关于ijkplayer下载的demo不能运行,这是因为FFmpeg
前提是你在Mac上已经配置了 homebrew 包管理工具 关于ijkPlayer的demo和framework的使用,也许当直接下载下来不能使用,这时候你需要再你下载的当前目录下运行,你看下自己的目 ...