开发Hadoop应用程序
1.Hadoop API组成
Hadoop API被分成(divide into)如下几种主要的包(package)
序号 | 名称 | 说明 |
1. | org.apache.hadoop.conf | 定义了系统参数的配置文件处理API。 |
2. | org.apache.hadoop.fs | 定义了抽象的文件系统API。 |
3. | org.apache.hadoop.dfs | Hadoop分布式文件系统(HDFS)模块的实现。 |
4. | org.apache.hadoop.io | 定义了通用的I/O API,用于针对网络,数据库,文件等数据对象做读写操作。 |
5. | org.apache.hadoop.ipc | 用于网络服务端和客户端的工具,封装了网络异步I/O的基础模块。 |
6. | org.apache.hadoop.mapred | Hadoop分布式计算系统(MapReduce)模块的实现,包括任务的分发调度等。 |
7. | org.apache.hadoop.metrics | 定义了用于性能统计信息的API,主要用于mapred和dfs模块。 |
8. | org.apache.hadoop.record | 定义了针对记录的I/O API类以及一个记录描述语言翻译器,用于简化将记录序列化成语言中性的格式(language-neutral manner)。 |
9. | org.apache.hadoop.tools | 定义了一些通用的工具。 |
10. | org.apache.hadoop.util | 定义了一些公用的API。 |
详细的API文档请见:http://hadoop.apache.org/common/docs/r0.20.2/api/(非常重要)
2.WordCount源程序分析
package org.apache.hadoop.examples;
import java.io.IOException;
import java.io.PrintStream;
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.Mapper.Context;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Reducer.Context;
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);
}
/**
* JobConf:map/reduce的job配置类,向hadoop框架描述map-reduce执行的工作
* 构造方法:JobConf()、JobConf(Class exampleClass)、JobConf(Configuration conf)等
*/
Job job = new Job(conf, "word count"); //配置作业名
job.setJarByClass(WordCount.class); //配置各个作业类
job.setMapperClass(TokenizerMapper.class);//为job设置Mapper类
job.setCombinerClass(IntSumReducer.class);//为job设置Combiner类
job.setReducerClass(IntSumReducer.class); //为job设置Reduce类
job.setOutputKeyClass(Text.class);//为job的输出数据设置Key类
job.setOutputValueClass(IntWritable.class);//为job输出设置value类
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));//为map-reduce任务设置InputFormat实现类
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));//为map-reduce任务设置OutputFormat实现类
/**
* InputFormat描述map-reduce中对job的输入定义
* setInputPaths():为map-reduce job设置路径数组作为输入列表
* setInputPath():为map-reduce job设置路径数组作为输出列表
*/
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
//继承Reducer接口,设置reduce的输入类型为<Text,IntWrite>
//输出类型为<Text,IntWrite>
public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable>
{
private IntWritable result = new IntWritable();//result记录单词的频数
public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context)
throws IOException, InterruptedException
{
int sum = 0;
for (IntWritable val : values) { //对获取的<key,value-list>计算value的和
sum += val.get();
}
//将频数记录到result中
this.result.set(sum);
context.write(key, this.result);//收集结果
}
}
//继承Mapper接口,设置map的输入类型为<Object,Text>
//输出类型为<Text,IntWriteable>
public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
{ /*
* LongWritable, IntWritable, Text 均是 Hadoop 中实现的用于封装 Java 数据类型的类,这些类实现了WritableComparable接口,
* 都能够被串行化从而便于在分布式环境中进行数据交换,你可以将它们分别视为long,int,String 的替代品。
*/
private static final IntWritable one = new IntWritable(1);//one表示单词出现一次
private Text word = new Text(); //word存储切下的单词
/**
* Mapper接口中的map方法:
* void map(K1 key, V1 value, OutputCollector<K2,V2> output, Reporter reporter)
* 映射一个单个的输入k/v对到一个中间的k/v对
* 输出对不需要和输入对是相同的类型,输入对可以映射到0个或多个输出对。
* OutputCollector接口:收集Mapper和Reducer输出的<k,v>对。
* OutputCollector接口的collect(k, v)方法:增加一个(k,v)对到output
*/
public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString()); //对输入的行切词
while (itr.hasMoreTokens()) {
this.word.set(itr.nextToken()); //切下的单词存入word
context.write(this.word, one);
}
}
}
}
3.Hadoop的程序开发过程
(1)系统参数的配置(这里我们需要用到的是org.apache.hadoop.conf用它来定义系统参数的配置configurations类由源来设置。每个源包含以xml形式出现的一系列属性/值对。每个源以一个字符串或一个路径来命名。如果以字符串命名,则类路径检查该字符串代表的路径存在与否;如果是以路径命名则直接通过本地文件系统进行检查,而用不着路径对于不同的资源属性的整合遵循后添加进来的属性覆盖掉前面添加的的资源属性取值,但是有一个特例被标记为final的属性不能被重写,重写标记为final的属性通常情况下会报告配置错误,同时会有警告信息被记录下来以便诊断所用。管理员将守护进程地址文件之中的属性标记为final,可以防止用户在客户端进行配置文件中或在作业提交参数中改变其取值,Hadoop默认使用两个源进行配置,并按顺序加载core-default.xml和core-site.xml。在实际应用中可能还会添加其他的源,并按他们添加的顺序进行加载。其中core-default .xml定义系统默认的属性,core-site.xml定义在特定的地方进行重写)
(2)配置开发环境(此过程在搭建Hadoop环境中已经进行了简处理,所以可以通过直接修改文件实现,大家可以看看Hadoop开发环境的配置中配置文件的那一步)
(3)编写Map-Reduce程序(后期我会提供更多的已经编写好并分析好的Map-Reduce程序供大家参考学习)
(4)运行MapReduce程序(1.需要把已经写好的Map-Reduce程序进行编译,编译完成后形成三个.class文件,在通过命令行进行打包,三个文件变成一个.jar文件下面可以想运行例子程序一样在本地上运行无误后,在完全分布式集群上运行我们写的程序,具体的操作方法和在Hadoop运行环境搭建的文章中过程类似,大家可以参考)
(5)网络用户界面的应用(即通过 WEB浏览器观察主节点从节点以及整个任务的运行情况,因为牵扯的内容比较多具体的使用情况我会在操作演示时现场演示给大家看)
(6)性能调优(能调优主要包括两个方面一个是时间性能,一个是空间性能。衡量性能的指标就是能够在正确完成功能的基础上,使执行的时间尽量的短,占用的空间尽量的小 ,性能调优主要从三个方面见来考虑,这两个方面也是最简单的两个方面,一是输入文件尽可能采用大文件,避免使用小文件,二是考虑压缩文件,三是修改配置文件中的相关属性,具体怎样修改配置以及怎么配置最好我会在实例讲解的时候给大家演示)
(7)MapReduce的工作流(不是很懂,正在研究,sorry )
----------冯现玉
2012.3.28