叫你写mapreduce--lesson2
来源:互联网 发布:刷火车票的软件 编辑:程序博客网 时间:2024/04/29 18:00
MapReduce第二节
还记得上一节的一个mr例子吗,对文件进行排序
#bin/hadoop jarcontrib/streaming/hadoop-streaming-1.2.1.jar -D mapred.compress.map.output=truemapred.job.reuse.jvm.num.tasks=4 -input/wolf1 -output /wolf2 -mapper /bin/cat -reducer /bin/cat
这里我们指定了几个参数–input 这里是指定文件输入目录
-output 这里是指定reduce结果输出目录
一、用java写mapreduce
1.1、自定义map函数
Mapreduce框架提供了map接口,实现这个接口,就自定义了map函数
publicclass Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
publicclass Context
extends MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
public Context(Configuration conf, TaskAttemptID taskid,
RecordReader<KEYIN,VALUEIN> reader,
RecordWriter<KEYOUT,VALUEOUT> writer,
OutputCommitter committer,
StatusReporter reporter,
InputSplit split) throws IOException, InterruptedException {
super(conf, taskid, reader, writer, committer, reporter, split);
}
}
/**
* 初始化方法,仅被调用一次,在map函数运行之前
*/
protectedvoid setup(Context context);
/**
* map函数
*/
protectedvoid map(KEYIN key, VALUEIN value, Context context){
context.write((KEYOUT) key, (VALUEOUT) value);
}
/**
*清理函数,map任务运行结束后,仅被调用一次
*/
protectedvoid cleanup(Context context)
/**
* 运行函数,map任务的入口
*/
publicvoid run(Context context) {
setup(context);
try {
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
} finally {
cleanup(context);
}
}
}
1.2、自定义reduce函数
Mapreduce框架提供了reduce接口,实现这个接口,就自定义了reduce函数
publicclass Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
publicclass Context
extends ReduceContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
public Context(Configuration conf, TaskAttemptID taskid,
RawKeyValueIterator input,
Counter inputKeyCounter,
Counter inputValueCounter,
RecordWriter<KEYOUT,VALUEOUT> output,
OutputCommitter committer,
StatusReporter reporter,
RawComparator<KEYIN> comparator,
Class<KEYIN> keyClass,
Class<VALUEIN> valueClass
) throws IOException, InterruptedException {
super(conf, taskid, input, inputKeyCounter, inputValueCounter,
output, committer, reporter,
comparator, keyClass, valueClass);
}
}
/**
*初始化方法,仅被调用一次,在map函数运行之前
*/
protectedvoid setup(Context context);
/**
* reduce函数
*/
protectedvoid reduce(KEYIN key, Iterable<VALUEIN> values, Context context){
for(VALUEIN value: values) {
context.write((KEYOUT) key, (VALUEOUT) value);
}
}
/**
* 清理函数,reduce任务运行结束后,仅被调用一次
*/
protectedvoid cleanup(Context context;
/**
* reduce任务入口
*/
publicvoid run(Context context)throws IOException, InterruptedException {
setup(context);
try {
while (context.nextKey()) {
reduce(context.getCurrentKey(), context.getValues(), context);
}
} finally {
cleanup(context);
}
}
}
1.3、利用InputFormat定义map输入
Map的输入数据从哪儿来呢?答案是可以从任何地方,hdfs文件、oracle、hbase等等。为map变出数据的魔术师正是----InputFormat。
只要实现InputFormat接口,就可以为Map指定输入。
publicabstractclassInputFormat<K, V> {
/**
* 将输入数据切分成多个InputSplit
*/
publicabstract
List<InputSplit> getSplits(JobContext context);
/**
* 为InputSplit创建读取类:RecordReader
*/
publicabstract
RecordReader<K,V> createRecordReader(InputSplit split,
TaskAttemptContext context
);
}
1.4、利用outPutFormat定向reduce输出
那么redcue输出结果,放到哪儿呢?可以是任何地方,hdfs、oralcle、hbase等等。
只要实现outPutFormat接口,就可以指定输出。
publicabstractclass OutputFormat<K, V> {
/**
* 获取RecordWriter
* @param context存储当前任务相关信息.
*/
publicabstract RecordWriter<K, V>
getRecordWriter(TaskAttemptContext context
) throws IOException, InterruptedException;
/**
*
*/
publicabstractvoid checkOutputSpecs(JobContext context
) throws IOException,
InterruptedException;
/**
*
*/
publicabstract
OutputCommitter getOutputCommitter(TaskAttemptContext context
) throws IOException, InterruptedException;
}
1.5、现成的InputFormat、outputFormat
编写InputFormat、outputform并不轻松,考虑到多种数据源,工作量可想而知,好在hadoop为我们提供了多种实现。
1.5.1 InputFormat
名称
数据来源
Key
Value
TextInputFormat
hdfs文件
LongWritable:行号
Text:文件里面一行内容
OracleDataDrivenDBInputFormat
Oracle表
LongWritable:行号
Textends DBWritable(resultset)
MultiTableInputFormat
多张hbase表
ImmutableBytesWritable:行键
org.apache.hadoop.hbase.client.Result
:Result
1.5.2 OutputFormat
名称
数据输出
Key
Value
TextOutputFormat
hdfs文件
Text
或者实现toString方法
Text
或者实现toString方法
DBOutputFormat
Oracle表
Textends DBWritable
无意义
MultiTableInputFormat
多张hbase表
ImmutableBytesWritable:表名
Put:向hbase写操作
Delete:向hbase删除操作
1.6 实现一个简单的MR
1.6.1 功能
从base_netizen_register表提取属性关联关系,对相同网民的属性建立关联关系,输出到hdfs文件中。
陈永鑫 11003 15804250106 11031
表名
base_netizen_register
字段名
类型
中文注释
数据1
数据2
数据3
NETIZEN_ID
VARCHAR2(255)
网民id
chenyongxin0321
chenyongxin0321
chenyongxin0321
WEBSITE
VARCHAR2(255)
网站域名
my.51job.com
my.51job.com
my.51job.com
ATTRIBUTE_TYPE
INTEGER
属性类型
11003
11031
11097
ATTRIBUTE_VALUE
VARCHAR2(4000)
属性值
陈永鑫
15804250106
210111198703212537
1.6.2实现
1.6.2.1 map函数
package test;
import java.io.IOException;
import java.sql.SQLException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
publicclass testMapextends org.apache.hadoop.mapreduce.Mapper<LongWritable, DbRow,Text,Text>{
publicvoid map(LongWritable key, DbRow value,
Context context) throws IOException, InterruptedException{
try {
Text oKey = new Text(value.values.getString("netizen_id") +"_"
+ value.values.getString("website") );
String oValue = value.values.getString("attribute_type")
+ "\t"
+ value.values.getString("attribute_value");
context.write(oKey, new Text(oValue));
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
}
1.6.2.2 reduce函数
package test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.io.Text;
publicclass testReduceextends
org.apache.hadoop.mapreduce.Reducer<Text ,Text, Text, Text> {
publicvoid reduce(Text key, Iterable<Text> values,
Context context) throws IOException, InterruptedException{
List<String> attrs = new ArrayList<String>();
for(Text t1:values)
attrs.add(t1.toString());
for(String t1:attrs){
String[] attr1 = t1.split("\t",10);
Text outkey = new Text(attr1[1] +"_" + attr1[0]);
for(Stringt2:attrs){
if(t1.equals(t2)){
continue;
}
String[] attr2 = t2.split("\t",10);
context.write(outkey, new Text(attr2[1] +"_" + attr2[0]));
}
}
}
}
1.6.2.3 main函数
package test;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBWritable;
import org.apache.hadoop.mapreduce.lib.db.OracleDataDrivenDBInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
publicclass Main {
static Log_log = LogFactory.getLog(Main.class);
publicstaticvoid main(String[] args)throws IOException, InterruptedException, ClassNotFoundException{
Configuration conf = new Configuration();
Job job = new Job(conf,"NeEt" );
/*
* 设置map
*/
job.setInputFormatClass(OracleDataDrivenDBInputFormat.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setMapperClass(testMap.class);
/*
* 设置reduce
*/
job.setOutputFormatClass(TextOutputFormat.class);
FileOutputFormat.setOutputPath(job, new Path("/wolf1/"));
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setReducerClass(testReduce.class);
job.setNumReduceTasks(1);
/*
* 设置oracle相关配置
*/
job.getConfiguration().set(DBConfiguration.URL_PROPERTY,"jdbc:oracle:thin:@15.15.17.68:1521:ora11g");
job.getConfiguration().set(DBConfiguration.USERNAME_PROPERTY,"noahdbn");
job.getConfiguration().set(DBConfiguration.PASSWORD_PROPERTY,"noahdbn");
job.getConfiguration().set(DBConfiguration.DRIVER_CLASS_PROPERTY,"oracle.jdbc.driver.OracleDriver" );
job.getConfiguration().set(DBConfiguration.INPUT_TABLE_NAME_PROPERTY," base_netizen_register ");
job.getConfiguration().set(DBConfiguration.INPUT_FIELD_NAMES_PROPERTY," netizen_id,website,attribute_type,attribute_value,capturetime,datasource ");
String cond = " 1 = 1 and rownum < 100 ";
job.getConfiguration().set(DBConfiguration.INPUT_CONDITIONS_PROPERTY, cond);
job.getConfiguration().setClass(DBConfiguration.INPUT_CLASS_PROPERTY, DbRow.class, DBWritable.class);
_log.info("sql:" +"select " + conf.get(DBConfiguration.INPUT_FIELD_NAMES_PROPERTY) +" from "
+ conf.get(DBConfiguration.INPUT_TABLE_NAME_PROPERTY) +" where " + cond);
/*
*
*/
job.setJarByClass(test.Main.class);
DistributedCache.addArchiveToClassPath(new Path("/wfp/ojdbc5.jar")
, job.getConfiguration()
, FileSystem.get(job.getConfiguration()));
/*
* 运行
*/
job.waitForCompletion(true);
}
}
二、MR调试
2.1 常见错误
错误名称
发送时间点
错误原因
解决办法
Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory /wolf1 already exists
任务启动前(准备期间)
输出目录已经存在,
删除输出目录
java.lang.RuntimeException: java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
任务启动前(准备期间)
我们自己的类库,没有加入的hadoop安装目录的lib下面
将我们自己调用的jar包拷贝到hadoop lib目录下
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
任务启动后
找不到我们依赖jar包的类
DistributedCache.addArchiveToClassPath(new Path("/wfp/ojdbc5.jar")
, job.getConfiguration()
, FileSystem.get(job.getConfiguration()));
2.2 调试技巧
2.2.1 通过jobtracker页面查看mr运行情况
http://15.15.36.104:50030/jobtracker.jsp
2.2.1 如何打印调试信息
由于mr程序是分布式运行,查看调试信息比较困难,这里介绍一种方法,
在map、reduce函数,调用Systerm.out打印输出日志。然后可以通过页面查看调试信息
2.3 搭建elipse MR开发环境
1、拷贝Hadoop项目中的eclipse plugin jar文件到eclipse 安装目录plugin目录下
2、重启eclipse,配置hadoop installation directory。
如果安装插件成功,打开Window-->Preferens,你会发现Hadoop Map/Reduce选项,在这个选项里你需要配置Hadoop installation directory。配置完成后退出。
3.配置Map/Reduce Locations。
在Window-->Show View->other...,在MapReduce Tools中选择Map/ReduceLocations。
在Map/Reduce Locations(Eclipse界面的正下方)中新建一个Hadoop Location。在这个View中,点击鼠标右键-->New HadoopLocation。在弹出的对话框中你需要配置Location name,可任意填,如Hadoop,以及Map/ReduceMaster和DFS Master。这里面的Host、Port分别为你在mapred-site.xml、core-site.xml中配置的地址及端口。我的这两个文件中配置如下:
mapred-site.xml
[html] view plaincopy
- <property>
- <name>mapred.job.tracker</name>
- <value>matraxa:9001</value>
- </property>
core-site.xml:
[html] view plaincopy
- <property>
- <name>fs.default.name</name>
- <value>hdfs://matraxa:9000</value>
- </property>
最后的配置截图如下:
设置完成后,点击Finish就应用了该设置。然后,在最左边的Project Explorer中就能看到DFS的目录,如下图所示:
4、建立、运行hadoop程序
1、新建项目。
File-->New-->Other-->Map/Reduce Project
项目名可以随便取,如hadoopTest。
三 MR优化技巧
3.1 合理设置reduce、map数量
默认情况下,reduce数量为1,所以当reduce运行比较慢的时候,可以多设置reduce任务数量,提高性能
属性名称
类型
默认值
说明
mapred.reduce.tasks
Int
1
Reduce任务数量
mapred.map.tasks
Int
动态决定
可以人为设置
3.2 jvm重用
默认情况下,hadoop,每启动一个map或reduce任务,就启动一个新的jvm。
Jvm重用的好处?1、节省启动jvm时间 2、可以充分利用HotSpot JVM所用的运行时优化
属性名称
类型
默认值
说明
mapred.job.reuse.jvm.num.tasks
Int
1
在一个tasktracker上面给定作业的每个jvm可以运行的任务最大数
3.3推测式执行开关
什么是推测式执行?一个mr任务启动会,会检测map、reduce任务执行情况,如果一个map或reduce任务,运行得异常缓慢,则会开启一个相同的map或reduce任务,作为备份。
推测执行的好处?一个map任务可能由于网络、硬盘老化等问题,执行很慢,拖这个job后腿,推测式执行,开启一个备份,可以避免一个点的异常状况。
坏处?开启备份,会造成资源浪费,有些时候,任务执行慢,无法避免,开启备份还是慢,并且占用宝贵的资源
属性名称
类型
默认值
说明
mapred.map.tasks.speculative.execution
Boolean
True
一个map任务运行缓慢时,是否开启一个备份
mapred.reduce.tasks.speculative.execution
Boolean
True
一个reduce任务运行缓慢时,是否开启一个备份
3.4对Map输出数据压缩(数据量大时)
属性名称
类型
默认值
说明
mapred.compress.map.output
Boolean
False
对map输出结果压缩
mapred.map.output.compression.codec
String
org.apache.hadoop.io.compress.DefaultCodec
编码格式
3.5Map端可调整的属性
属性名称
类型
默认值
说明
io.sort.mb
int
100
对Map端输出进行排序时所使用的内存大小,单位M
io.sort.record.percent
Float
0.05
io.sort.mb内存预留一部分给,来记录map的输出边界
io.sort.spill.percent
Float
0.8
io.sort.mb内存使用达到多少,将缓存数据写到磁盘
Io.sort.factor
int
10
排序文件时,一次合并的最大流数
Min.num.spills.for.combine
int
3
运行combiner所需要的最少文件数量(如果设置了combinber)
tasktracker.http.threads
Int
40
Tasktracker开启的数据复制线程数(赋值map数据给reduce)
3.6 redue端可调整的属性
属性名称
类型
默认值
说明
mapred.reduce.parallel.copies
int
5
用于将map输出复制到reducer的线程数量
Io.sort.factor
int
10
排序文件时,一次合并的最大流数
mapred.job.shuffle.input.buffer.percent
Float
0.70
整个堆空间的百分比,用于shuffle的赋值阶段
mapred.job.shuffle.merge.percent
Float
0.66
map输出缓存,使用达到这个比例,启动合并输出到磁盘
mapred.inmem.merge.threshold
Int
1000
启动合并,最大map输出量
mapred.job.reduce.input.buffer.percent
Float
0
在reduce过程中,用来在内存中保存map输出空间占整个堆空间的比例
Stream
属性名
属性值
描述
mapred.input.dir
hdfs://15.15.36.104:9000/wolf1
输入文件目录
mapred.input.format.class
org.apache.hadoop.mapred.TextInputFormat
mapred.mapper.class
org.apache.hadoop.streaming.PipeMapper
stream.map.streamprocessor
/bin/cat
Stream的map函数
mapred.mapoutput.key.class
org.apache.hadoop.io.Text
Map函数输出key类型
mapred.mapoutput.value.class
org.apache.hadoop.io.Text
Map函数输出value类型
mapred.output.dir
hdfs://15.15.36.104:9000/wolf2
输出文件目录
mapred.output.format.class
org.apache.hadoop.mapred.TextOutputFormat
mapred.reducer.class
org.apache.hadoop.streaming.PipeReducer
stream.reduce.streamprocessor
/bin/cat
Stream 的 reduce函数
mapred.output.key.class
org.apache.hadoop.io.Text
Reduce输出的Key类型
mapred.output.value.class
org.apache.hadoop.io.Text
Reduce输出的value类型
Pipes
属性名
属性值
描述
mapred.input.dir
hdfs://15.15.36.104:9000/temp
输入文件目录
mapred.input.format.class
org.apache.hadoop.mapred.pipes.PipesNonJavaInputFormat
mapred.map.runner.class
org.apache.hadoop.mapred.pipes.PipesMapRunner
mapred.mapoutput.key.class
org.apache.hadoop.io.Text
Map函数输出key类型
mapred.mapoutput.value.class
org.apache.hadoop.io.Text
Map函数输出value类型
mapred.output.dir
hdfs://15.15.36.104:9000/x
输出文件目录
mapred.output.format.class
org.apache.hadoop.mapred.lib.NullOutputFormat
mapred.reducer.class
org.apache.hadoop.mapred.pipes.PipesReducer
stream.reduce.streamprocessor
/bin/cat
Stream 的 reduce函数
mapred.output.key.class
org.apache.hadoop.io.Text
Reduce输出的Key类型
mapred.output.value.class
org.apache.hadoop.io.Text
Reduce输出的value类型
- 叫你写mapreduce--lesson2
- 手把手叫你写自定义ProgressDialog控件
- lesson2
- lesson2
- lesson2
- lesson2
- 就叫你美工
- 叫你快速阅读
- 叫你快速阅读
- 你学什么叫?
- 程序员写的叫struts
- 叫你一声Mylove
- 喜欢你这样叫我~
- 叫你宝贝的那个人。。。
- 你知道什么叫“打工仔”
- lesson2&3
- LogicJava---Lesson2
- VC++ lesson2
- volatile static
- dataTable 操作某条数据后刷新是否保留在当前页的方法
- XCode编译器介绍
- Cocos2d-x XML文件读取操作与解析操作
- Linux 进程间通信 --- 信号通信 --- signal
- 叫你写mapreduce--lesson2
- 在平板导航栏添加屏幕截图功能
- 50个C++源码学习网站
- EJB到底是什么,真的那么神秘吗??
- iphone6的传言与实际对比
- 你好,C++(7)第三部分 C++世界众生相 3.2.1 变量的定义与初始化
- Windows开机自动运行软件及自动重启
- yii 验证码的使用和验证过程
- 数据库中带html标签的数据,以及有大段空格的数据