12月8日 第18天
1.典型MapReduce程序的每个阶段
2.hadoop的数据类型
MapReduce框架提供了一种序列化键/值对的方法,只有那些支持这种序列化的类能够在这个框架中充当键或值。
也可以自定义数据类型,只要实现了Writable或WritableComparable接口,WritableComparable接口是Writable和java.long.Comparable接口的组合。实现Writable接口的类可以是值,实现WritableComparable接口的类可以是键也可以是值。
自定义数据类型代码:
3.Mapper
一个类要作为Mapper,需要继承MapReduceBase基类,实现Mapper接口。
voidconfigure(JobConf conf) —— 处理数据前调用,提取xml文件和主类中的参数
void close()—— 最后一个操作,关闭数据库,打开文件等
Mapper的形式为Mapper用于处理一个单独的键/值对。
4.Reducer
和Mapper一样,必须先在MapReduce基类上扩展,实现接口Reducer,使其具有如下的单一方法:
流程为:各个Mapper输出→reducer接收→按键排序→相同键值归并→reduce()
1.典型MapReduce程序的每个阶段
2.hadoop的数据类型
| |
| |
| |
| |
| |
| |
| |
| |
表1键/值对常使用的数据类型列表(都实现WritableComparable接口)
自定义数据类型代码:
package org.apache.hadoop.examples;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
public class Edge implements WritableComparable{
privateString departureNode;
privateStringarrivalNode;
//departureNode的get方法
publicString getDepartureNode() {
returndepartureNode;
}
//如何读入数据
@Override
public voidreadFields(DataInput in) throws IOException {
departureNode = in.readUTF();
arrivalNode= in.readUTF();
}
//如何写出数据
@Override
public voidwrite(DataOutput out) throws IOException {
out.writeUTF(departureNode);
out.writeUTF(arrivalNode);
}
//定义数据排序
@Override
public intcompareTo(Edge o) {
//三目运算符:表达式1真返回表达式2,假返回表达式3
return(departureNode.compareTo(o.departureNode) != 0) ?departureNode.compareTo(o.departureNode) :arrivalNode.compareTo(o.arrivalNode);
}
}
3.Mapper
void map(
K1 key, //键值对(K1,V1)
V1 value,
OutputCollector output, //生成键值对(K2,V2)的列表,output接受这个映射过程的输出
Reporter reporter //提供记录,形成任务进度
)throws IOException
| 实现Mapper,将输入直接映射到输出 |
| |
| |
| |
表2常用的hadoop预定义的Mapper实现
4.Reducer
void reduce(
K2 key, //给定的键
Iterator values, //迭代出与键相关的值
OutputCollector output, //生成(K3,V3),用output接收、写入输出文件
Reporter reporter //reduce相关信息记录,形成任务进度
)throws IOException
| |
| 实现,计算与给定键相对应的所有值的和 |
表3常用的hadoop预定义的Reducer实现
5.Partitioner
重定向Mapper输出(将Mapper的结果输出给不同的reducer)。
初次使用MapReduce的程序猿通常有一个误解,以为仅需使用一个reducer,但是,当使用多个reducer时,我们需要采取一些办法来确定mapper应该把键/值对输出给谁,这时候就需要定制partitioner了。
定制partitioner方法:
①实现Partitioner接口(implements Partitioner)
②实现configure(),将hadoop对作业的配置应用在patitioner上
③实现getPartition(),返回0和reduce任务数之间的整数,指向键/值对将要发送到的reducer
实现定制partitioner代码:
6.Combiner
本地reducer(略)。
7.使用预定义的mapper和reducer类完成单词计数
5.Partitioner
实现定制partitioner代码:
package org.apache.hadoop.examples;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.Partitioner;
public class EdgePartitioner implements Partitioner{
@Override
public voidconfigure(JobConf conf) {}
@Override
public intgetPartition(Edge key, Writable value, int numPartitions) {
returnkey.getDepartureNode().hashCode() % numPartitions;
}
}
6.Combiner
7.使用预定义的mapper和reducer类完成单词计数
package org.apache.hadoop.examples;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.lib.LongSumReducer;
import org.apache.hadoop.mapred.lib.TokenCountMapper;
importcom.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider.Text;
public class WordCount2 {
publicstatic void main(String[] args){
JobClientclient = new JobClient();
JobConf conf= new JobConf(WordCount2.class);
FileInputFormat.addInputPath(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
conf.setOutputKeyClass(Text.class);
conf.setOutputValueClass(LongWritable.class);
//使用预定义的类TokenCountMapper当输入的值为分词时,生成一个(token,1)对
conf.setMapperClass(TokenCountMapper.class);
//预定义的类LongSumReducer计算与给定健相对应的所有值和
conf.setCombinerClass(LongSumReducer.class);
conf.setReducerClass(LongSumReducer.class);
client.setConf(conf);
try{
JobClient.runJob(conf);
}catch(Exception e){
e.printStackTrace();
}
}
}