Hadoop自身使用一个配置对象类存储所有作业的配置属性,也可以使用这个对象将参数传递到Mapper和Reducer
Configuration类(JonConf的父类)有许多通用的setter方法,属性采用键值对的形式,键必须是string,而值可以是常用类型的任意一个。
常用的setter方法:
public void set(String name,String value)
public void setBoolean(String name, boolean value)
public void setInt(String name, int value)
public void setLong(String name, long value)
public void setStrings(String name, String... values)
常用的getter方法:
public String get(String name)
public String get(String name, String defaultValue)
public boolean getBoolean(String name, boolean defaultValue)
public float getFloat(String name, float defaultValue)
public int getInt(String name, int defaultValue)
public long getLong(String name, long defaultValue)
public String getBoolean(String name, String... defaultValue)
Tips:在Hadoop内部,所有的属性都存为字符串
package MR;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.*;
import java.io.IOException;
import java.util.Iterator;
/**
* Created by Promacanthus on 2017/6/29.
*/
public class tample {
public int run(String[] args)throws Exception{
Configuration conf = new Configuration();
JobConf job = new JobConf(conf);
job.setInt("myjob.property",Integer.parseInt(args[2]));
JobClient.runJob(job);
return 0;
}
public static class MapClass extends MapReduceBase implements Mapper<Text,Text,Text,Text>{
int myproperty;
public void configure(JobConf job){
myproperty = job.getInt("myjob.property",0);
}
public void map(Text key, Text value, OutputCollector output, Reporter reporter) throws IOException {
}
}
public static class Reduc extends MapReduceBase implements Reducer<Text,Text,Text,Text>{
int myproperty;
public void configure(JobConf job){
myproperty = job.getInt("myjob.property",0);
}
public void reduce(Text key, Iterator values, OutputCollector output, Reporter reporter) throws IOException {
}
}
}
当允许用户设定特定属性时,在driver中最好针对用户的输入进行验证
除了获取自定义属性和全局配置外,可以使用配置对象上的getter方法获得当前任务和作业状态的一些信息
例如,通过map.input.file属性来得到当前mao任务的文件路径
在配置对象中可获得的任务特定状态信息:
属性 | 类型 | 描述 |
---|---|---|
maperd.job.id | String | 作业ID |
mapred.jar | String | 作业目录中jar的位置 |
job.local.dir | String | 作业的本地空间 |
mapred.tip.id | String | 任务ID |
mapred.task.id | String | 任务重试ID |
mapred.task.is.map | boolean | 标志量,表示是否为一个map任务 |
mapred.task.partition | int | 作业内部的任务ID |
map.input.file | String | Mapper读取的文件路径 |
map.input.start | long | 当前Mapper输入分片的文件偏移量 |
map.input.length | long | 当前Mapper输入分片中的字节数 |
mapred.work.output.dir | String | 任务的工作(即临时)输出目录 |
默认情况下,所有的MR作业都输出一组文件。然而在有些场景下,输出多组文件或把一个数据集分为多个数据集更为方便
3-1、MultipleOutputFormat
MultipleOutputFormat提供了一个简单的方法,将相似的记录结组为不同的数据集,在写每条输出记录之前,这个outputFormat类调用一个内部方法来确定要写入的文件名
更具体的说,扩展MultipleOutputFormat的某个子类,并实现generateFileNameKeyValue()方法,扩展的子类将决定输出的格式。
类 | 输出格式 |
---|---|
MultipleTextOutputFormat | 输出文本文件 |
MultipleSequenceFileOutputFormat | 输出序列文件 |
不论扩展了哪一个子类,都需要重写下面的方法以返回每个输出键值对的文件名:
protected String generateFileNameForKeyValue(K key,V value, String name)
默认实现返回参数name,即文件名
示例代码如下:
package HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.mapred.lib.MultipleTextOutputFormat;
import org.apache.hadoop.util.Tool;
import java.io.IOException;
/**
* Created by Promacanthus on 2017/6/29.
*/
public class MultiFile extends Configured implements Tool {
public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, NullWritable, Text> {
public void map(LongWritable key, Text value, OutputCollector output, Reporter reporter) throws IOException {
output.collect(NullWritable.get(), value);
}
}
public static class PartitionByCountryMTOF extends MultipleTextOutputFormat<NullWritable, Text> {
protected String generateFielNameForKeyValue(NullWritable key, Text value, String filename) {
String[] arr = value.toString().split(",", -1);
String country = arr[4].substring(1, 3);
return country + "/" + filename;
}
}
public int run(String[] args) throws Exception {
Configuration conf = getConf();
JobConf job = new JobConf();
Path in = new Path(args[0]);
Path out = new Path(args[1]);
FileInputFormat.setInputPathFilter(job,in);
FileOutputFormat.setOutputPath(job,out);
job.setJobName("MultiFile");
job.setMapperClass(MapClass.class);
job.setInputFormat(TextInputFormat.class);
job.setOutputFormat(PartitionByCountryMTOF.class);
job.setOutputKeyClass(NullWritable.class);
job.setOutputValueClass(Text.class);
job.setNumReduceTasks(0);
JobClient.runJob(job);
return 0;
}
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(),new MultiFile(),args);
System.exit(res);
}
在输入出目录中可以看到每个国家都有一个单独的目录
3-2、MultipleOutputs
MultipleOutputs不要求给每条记录请求文件名,而是创建多个OutputCollector,每个OutputCollector可以有自己的OutputFormat和键值对类型,MR程序决定如何向每个OutputCollector输出数据
示例代码如下:
package HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.mapred.lib.MultipleOutputs;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.io.IOException;
/**
* Created by Promacanthus on 2017/6/29.
*/
public class NewMultipleFile extends Configured implements Tool {
public static class MapClass extends MapReduceBase implements Mapper {
private MultipleOutputs mos;
private OutputCollector collector;
public void configure(JobConf conf) {
mos = new MultipleOutputs(conf);
}
public void map(LongWritable key, Text value, OutputCollector output, Reporter reporter) throws IOException {
String[] arr = value.toString().split(",", -1);
String chrono = arr[0] + "," + arr[1] + "." + arr[2];
String geo = arr[0] + "," + arr[4] + "." + arr[5];
collector = mos.getCollector("chrono", reporter);
collector.collect(NullWritable.get(), new Text(chrono));
collector = mos.getCollector("geo", reporter);
collector.collect(NullWritable.get(), new Text());
}
public void close() throws IOException {
mos.close();
}
}
public int run(String[] args) throws Exception {
Configuration conf = getConf();
JobConf job = new JobConf(conf,MultiFile.class);
Path in = new Path(args[0]);
Path out = new Path(args[1]);
FileInputFormat.setInputPaths(job,in);
FileOutputFormat.setOutputPath(job,out);
job.setJobName("MultiFile");
job.setMapperClass(MultiFile.MapClass.class);
job.setInputFormat(TextInputFormat.class);
job.setOutputFormat(MultiFile.PartitionByCountryMTOF.class);
job.setOutputKeyClass(NullWritable.class);
job.setOutputValueClass(Text.class);
job.setNumReduceTasks(0);
MultipleOutputs.addNamedOutput(job,"chrono",TextOutputFormat.class,NullWritable.class,Text.class);
MultipleOutputs.addNamedOutput(job,"gep",TextOutputFormat.class,NullWritable.class,Text.class);
JobClient.runJob(job);
return 0;
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(),new MultiFile(),args);
System.exit(res);
}
}
若要使用MultipleOutputs,MR程序的driver类必须设置它想要使用的输出收集器
在输出目录中有一组以chrono为前缀的文件,另一组以geo为前缀的文件
DBOutputFormat是访问数据库的关键类,在driver类中将输入输出格式设置为这个类,指定配置,便能够连接到该数据库了。具体配置通过DBConfiguration中的静态方法configureDB():
public static void configureDB(JobConf job, String driverClass, String dbUrl, String userName, String passwd)
然后指定将要写入的表,以及哪些字段,使用DBOutputFormat中的今天方法setOutput():
public static void setOutput(JobConf job, String tableName, String... fieldNames)
在driver类中添加如下代码:
job.setOutputFormat(DBOutputFormat.class);
DBConfiguration.configureDB(job,"com.mysql.jdbc.Driver","jdbc:mysql://db.host.com/mydb","username","password");
使用DBOutputFormat将强制输出的键实现DBWritable接口
Tips:从Hadoop内部读写数据库仅适用于凭借Hadoop标准来说相对较小的数据集,除非数据库和Hadoop并行,否则数据库将成为性能瓶颈
MR框架保证每个reducer的输入都按键来排序,在许多情况下,reducer只是对键值对中值的部分做简单的计算,输出仍然保持顺序排序。MR框架并不能保证reducer输出的顺序,它只是已经排序好的输入以及reducer锁执行的操作类型的副产品
如何让reducer的输出时有序的呢,即part-r-00000中所有记录小于part-r-00001,以此类推?关键在于Partitioner操作
TotalOrderPartitioner是一个可以保证在输入分区之间,而不仅仅是分区内部排序的Partitioner,这个类利用一个排好序的分区键组读取一个序列文件,并进一步将不同区域的键分配到reducer上