7.1概述
1、MapReduce计数器是什么?
计数器是用来记录job的执行进度和状态的。它的作用可以理解为日志。我们可以在程序的某个位置插入计数器,记录数据或者进度的变化情况。
2、MapReduce计数器能做什么?
MapReduce 计数器(Counter)为我们提供一个窗口,用于观察 MapReduce Job 运行期的各种细节数据。对MapReduce性能调优很有帮助,MapReduce性能优化的评估大部分都是基于这些 Counter 的数值表现出来的。
3、MapReduce 都有哪些内置计数器?
MapReduce 自带了许多默认Counter,现在我们来分析这些默认 Counter 的含义,方便大家观察 Job 结果,如输入的字节数、输出的字节数、Map端输入/输出的字节数和条数、Reduce端的输入/输出的字节数和条数等。下面我们只需了解这些内置计数器,知道计数器组名称(groupName)和计数器名称(counterName),以后使用计数器会查找groupName和counterName即可。
7.2计数器使用
1.定义计数器
枚举声明计数器:
//自定义枚举变量Enum
Counter counter=context.getCounter(Enum enum)
自定义计数器:
//自己命名groupName和counterName
Counter counter=context.getCounter(String groupName,String counterName)
2.为计数器赋值
初始化计数器:
counter.setValue(long value);//设置初始值
计数器自增:
counter.increment(long incr);//增加计数
3.获取计数器的值
获取枚举计数器的值:
Configuration conf=new Configuration();
Job job=new Job(conf,"MyCounter");
job.waitForCompletion(true);
Counters counters=job.getCounters();
//查找枚举计数器,假如Enum的变量为BAD_RECORDS_LONG
Counter counter=counters.findCounter(LOG_PROCESSOR_COUNTER.BAD_RECORDS_LONG);
long value=counter.getValue();//获取计数值
获取自定义计数器的值:
Configuration conf=new Configuration();
Job job=new Job(conf,"MyCounter");
job.waitForCompletion(true);
Counters counters=job.getCounters();
//假如groupName为ErrorCounter,counterName为toolong
Counter counter=counters.findCounter("ErrorCounter","toolong");
long value=context.getValue();//获取计数器值
获取内置计数器的值:
...
//假如groupName为org.apache.hadoop.mapreduce.JobCounter,couterName为TOTAL_LAUNCHED_REDUCES
Counter counter =counters.findCounter("org.apache.hadoop.mapreduce.JobCounter","TOTAL_LAUNCHED_REDUCES");
...
7.3自定义计数器
MapReduce允许用户编写程序来自定义计数器,计数器的值可以在Mapper或Reducer中增加。多个计数器有一个Java枚举(enum)类型来定义,以便对计数器分组。一个作业可以定义的枚举类型数量不限,各个枚举类型所包含的字段数量也不限。枚举类型的名称即为组的名称,枚举类型的字段就是计数器名称。计数器是全局的。换言之,MapReduce框架将跨所有map和reduce聚集这些计数器,并在作业结束时产生一个最终结果。
7.4实验
要求:假如一个文件,规范格式为3个字段,”\t"作为分隔符,其中有多于3个字段的定义为过长字段,小于3个的定义为过短字段,统计他们的个数
完整代码:
package lab7;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class Counters {
public static class MyCounterMap extends Mapper<LongWritable,Text,Text,Text>{
public static Counter ct=null;
protected void map(LongWritable key,Text value,Context context)throws IOException,InterruptedException{
String arr_value[]=value.toString().split("\t");
if(arr_value.length >3) {
ct=context.getCounter("ErrorCounter","toolong");
ct.increment(1);
}else if(arr_value.length<3) {
ct=context.getCounter("ErrorCounter","tooshort");
ct.increment(1);
}
}
}
public static void main(String[] args)throws IOException,InterruptedException,ClassNotFoundException{
Configuration conf=new Configuration();
String[] otherArgs=new GenericOptionsParser(conf,args).getRemainingArgs();
if(otherArgs.length !=2) {
System.err.println("Usage:Counters<in><out>");
System.exit(2);
}
Job job=new Job(conf,"Counter");
job.setMapperClass(MyCounterMap.class );
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job,new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true)?0:1);
}
}
输入文件:
jim 1 28
kate 0 26
tom 1
lily 0 29 32
输出结果(在Console中):
ErrorCounter
toolong=1
tooshort=1