Hadoop是一个由Apache基金会所开发的分布式系统基础架构,可以在不了解分布式底层细节的情况下,开发分布式程序,以满足在低性能的集群上实现对高容错,高并发的大数据集的高速运算和存储的需要。Hadoop支持超大文件(可达PB级),能够检测和快速应对硬件故障、支持流式数据访问、同时在简化的一致性模型的基础上保证了高容错性。因而被大规模部署在分布式系统中,应用十分广泛。
本实训的主要目标是让大家学习Hadoop的基本概念如MapReduce、HDFS等,并掌握Hadoop的基本操作,主要包括MapReduce编程(词频统计)、HDFS文件流读取操作、MapReduce迭代等。通过本次实训,建立起对Hadoop云计算的初步了解,后续大家可以通过进阶学习来深入学习Hadoop内部实现机制进行高级的应用开发。
第1关:WordCount词频统计:
词频统计是最能体现MapReduce
思想的程序,结构简单,上手容易。
词频统计的大致功能是:统计单个或者多个文本文件中每个单词出现的次数,并将每个单词及其出现频率按照<k,v>
键值对的形式输出,其基本执行流程如下图所示:
由图可知:
- 输入文本(可以不只一个),按行提取文本文档的单词,形成行
<k1,v1>
键值对,具体形式很多,例如<行数,字符偏移>
等; - 通过
Spliting
将<k1,v1>
细化为单词键值对<k2,v2>
; Map
分发到各个节点,同时将<k2,v2>
归结为list(<k2,v2>)
;- 在进行计算统计前,先用
Shuffing
将相同主键k2
归结在一起形成<k2,list(v2)>
; - Reduce阶段直接对
<k2, list(v2)>
进行合计得到list(<k3,v3>)
并将结果返回主节点。
主节点对预设文本文档进行词频统计,并将最终结果输出。
- 注:输入和输出事先已经预定,只要比较输出是否达到预期即可判断是否达到要求。
相关知识
MapReduce
采用"分而治之"的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个分节点共同完成,然后通过整合各个节点的中间结果,得到最终结果。MapReduce
框架负责处理了并行编程中分布式存储、工作调度、负载均衡、容错均衡、容错处理以及网络通信等复杂问题。将处理过程高度抽象为两个函数:map
和reduce
。
map负责把任务分解成多个任务;
reduce负责把分解后多任务处理的结果汇总起来。
- 注:
MapReduce
处理的数据集必须可以分解成许多小的数据集,而且每一个小数据集都可以完全并行地进行处理。不是关系型数据库,而是结构化的。
map处理阶段
对于给定的待处理文本文档,其map
阶段的处理如下:
- 通过
Text
对象,获取文本文档的内容。 - 逐行处理文档,将单词提取出来。
- 每个单词为key,对应的
value
设为1
,将<k2,v2>
对输出。
关键性说明:
map
阶段的处理,主要是如何对文本进行逐行的单词分割,从而获取单词,以及将键值对分发到各个节点(此处由hadoop
隐性提供,用户先不必关心hdfs
存储过程)。- 可以参考的单词分割提取代码模板如下:
public void map(Object key,Text value,Context context)throws IOException,InterruptedException
{
//对文本内容对象value进行分割
StringTokenizer itr=new StringTokenizer(valu e.toString());
while(itr.hasMoreTokens()) {
String word=itr.nextToken();/*获取分割好的单词*/
/*
可以在该循环体中,使用获取好的单词word变量进行key和value的设定。
*/
}
}
reduce处理阶段
在Wordcount
的reduce
阶段,主要是将每个单词的数量统计出来,包括:
- 在各个节点并行循环统计每个单词出现的次数。
- 将各个节点的结果汇总以
list(<k3,v3>)
的形式输出。
reduce
函数参考模板:
public void reduce(Object key,Iterable<IntWritable> values,Context context)throws IOException, InterruptedException
{
int count=0;
for(IntWritable itr:vlaues)
{
count+=itr.get(); /*循环统计*/
}
/*统计完成后,将结果输出.....*/
}
编程要求
本关的编程任务是补全右侧代码片段中map
和reduce
函数中的代码,具体要求及说明如下:
- 在主函数
main
中已初始化hadoop
的系统设置,包括hadoop运行环境的连接。 - 在
main
函数中,已经设置好了待处理文档路径(即input
),以及结果输出路径(即output
)。 - 在
main
函数中,已经声明了job
对象,程序运行的工作调度已经设定好。 - 本关只要求在
map
和reduce
函数的指定区域进行代码编写,其他区域请勿改动。
测试说明
以下是测试样例:
测试输入样例数据集:文本文档test1.txt
和test2.txt
-
文档test1.txt中的内容为:
tale as old as time
true as it can be
beauty and the beast
-
文档test2.txt中的内容为:
ever just the same
ever as before
beauty and the beast
预期输出result.txt
文档中的内容为:and 2
as 4
beast 2
beauty 2
before 1
can 1
ever 2
it 1
just 1
old 1
same 1
tale 1
the 3
time 1
true 1
代码:
import java.io.IOException;
import java.util.StringTokenizer;
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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
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 class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private 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);
}
/*********begin*********
/*********end**********/
}
}
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 {
/*********begin*********/
int sum = 0;
for (IntWritable val : values){
sum += val.get();
}
result.set(sum);
context.write(key,result);
/*********end**********/
/*********begin*********/
/*********end**********/
}
}
public static void main(String[] args) throws Exception {
/**
* JobConf£ºmap/reduceµÄjobÅäÖÃÀ࣬Ïòhadoop¿ò¼ÜÃèÊömap-reduceÖ´ÐеŤ×÷
* ¹¹Ôì·½·¨£ºJobConf()¡¢JobConf(Class exampleClass)¡¢JobConf(Configuration conf)µÈ
*/
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsPa