MapReduce分布式编程
- 实验目的及要求
本次上机实验所涉及并要求掌握的知识点
- 实验环境
Eclipse、Hadoop
- 实验步骤
MapReduce编程入门实例之WordCount:分别在Eclipse和Hadoop集群上运行
首先看一下我的项目结构和WordCount程序:
其中word.txt将作为我们测试的输入文件,内容如下:
hello hadoop
hello wordcount
程序代码:
package com.hadoop.WordCount;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
@SuppressWarnings("unused")
public class WordCount {
public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable>
// 为什么这里k1要用Object、Text、IntWritable等,而不是java的string啊、int啊类型,当然,你可以用其他的,这样用的好处是,因为它里面实现了序列化和反序列化。
// 可以让在节点间传输和通信效率更高。这就为什么hadoop本身的机制类型的诞生。
//这个Mapper类是一个泛型类型,它有四个形参类型,分别指定map函数的输入键、输入值、输出键、输出值的类型。hadoop没有直接使用Java内嵌的类型,而是自己开发了一套可以优化网络序列化传输的基本类型。
//这些类型都在org.apache.hadoop.io包中。
//比如这个例子中的Object类型,适用于字段需要使用多种类型的时候,Text类型相当于Java中的String类型,IntWritable类型相当于Java中的Integer类型
{
//定义两个变量或者说是定义两个对象,叫法都可以
private final static IntWritable one = new IntWritable(1);//这个1表示每个单词出现一次,map的输出value就是1.
//因为,v1是单词出现次数,直接对one赋值为1
private Text word = new Text();
public void map(Object key, Text value, Context context)
//context它是mapper的一个内部类,简单的说顶级接口是为了在map或是reduce任务中跟踪task的状态,很自然的MapContext就是记录了map执行的上下文,在mapper类中,这个context可以存储一些job conf的信息,比如job运行时参数等,
//我们可以在map函数中处理这个信息,这也是Hadoop中参数传递中一个很经典的例子,同时context作为了map和reduce执行中各个函数的一个桥梁,这个设计和Java web中的session对象、application对象很相似
//简单的说context对象保存了作业运行的上下文信息,比如:作业配置信息、InputSplit信息、任务ID等
//我们这里最直观的就是主要用到context的write方法。
//说白了,context起到的是连接map和reduce的桥梁。起到上下文的作用!
throws IOException, InterruptedException {
//The tokenizer uses the default delimiter set, which is " \t\n\r": the space character, the tab character, the newline character, the carriage-return character
StringTokenizer itr = new StringTokenizer(value.toString());//将Text类型的value转化成字符串类型
//使用StringTokenizer类将字符串“hello,java,delphi,asp,PHP”分解为单个单词
// 程序的运行结果为:
// hello
// java
// delphi
// asp
// php
while (itr.hasMoreTokens()) {
// 实际上就是java.util.StringTokenizer.hasMoreTokens()
// hasMoreTokens() 方法是用来测试是否有此标记生成器的字符串可用更多的标记。
word.set(itr.nextToken());
context.write(word, one);
}
}
}
public static class IntSumReducer extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException { 62 //我们这里最直观的就是主要用到context的write方法。
//说白了,context起到的是连接map和reduce的桥梁。起到上下文的作用!
int sum = 0;
for (IntWritable val : values) {//叫做增强的for循环,也叫for星型循环
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();//程序里,只需写这么一句话,就会加载到hadoop的配置文件了
//Configuration类代表作业的配置,该类会加载mapred-site.xml、hdfs-sit