MapReduce计数器实验

一、实验目的

  • 通过实验掌握基本的MapReduce编程方法;

  • 掌握用MapReduce解决一些常见的数据处理问题,编写计数器程序。

二、实验平台

  • 操作系统:Linux(建议CentOS6.5);

  • Hadoop版本:2.9.2;

  • JDK版本:1.8或以上版本;

  • Java IDE:Eclipse;

三、实验要求

能够理解MapReduce编程思想,然后会编写MapReduce版本计数器程序,并能执行该程序和分析执行过程。

四、实验背景

1、MapReduce计数器是什么?

计数器是用来记录job的执行进度和状态的。它的作用可以理解为日志。我们可以在程序的某个位置插入计数器,记录数据或者进度的变化情况。

2、MapReduce计数器能做什么?

MapReduce 计数器(Counter)为我们提供一个窗口,用于观察 MapReduce Job 运行期的各种细节数据。对MapReduce性能调优很有帮助,MapReduce性能优化的评估大部分都是基于这些 Counter 的数值表现出来的。

3、内置计数器

MapReduce 自带了许多默认Counter,现在我们来分析这些默认 Counter 的含义,方便大家观察 Job 结果,如输入的字节数、输出的字节数、Map端输入/输出的字节数和条数、Reduce端的输入/输出的字节数和条数等。下面我们只需了解这些内置计数器,知道计数器组名称(groupName)和计数器名称(counterName),以后使用计数器会查找groupName和counterName即可。

4、计数器使用

(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();

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();

Counter counter=counters.findCounter("ErrorCounter","toolong");// 假如groupName为ErrorCounter,counterName为toolong

//获取内置计数器的值:

long value = counter.getValue();

Configuration conf = new Configuration();

Job job = new Job(conf, "MyCounter");

job.waitForCompletion(true);

Counters counters=job.getCounters();

Counter counter=counters.findCounter("org.apache.hadoop.mapreduce.JobCounter","TOTAL_LAUNCHED_REDUCES") ;

long value=counter.getValue();

Configuration conf = new Configuration();

Job job = new Job(conf, "MyCounter");

Counters counters = job.getCounters();

for (CounterGroup group : counters) {
    
    

 for (Counter counter : group) {
    
    

  System.out.println(counter.getDisplayName() + ": " + counter.getName() + ": "+ counter.getValue());

 }

}

(5)自定义计数器

MapReduce允许用户编写程序来定义计数器,计数器的值可在mapper或reducer 中增加。多个计数器由一个Java枚举(enum)类型来定义,以便对计数器分组。一个作业可以定义的枚举类型数量不限,各个枚举类型所包含的字段数量也不限。枚 举类型的名称即为组的名称,枚举类型的字段就是计数器名称。计数器是全局的。换言之,MapReduce框架将跨所有map和reduce聚集这些计数器,并在作业结束 时产生一个最终结果。

五、实验步骤

1、实验分析设计

该实验要求学生自己实现一个计数器,统计输入的无效数据。说明如下:假如一个文件,规范的格式是3个字段,“\t”作为分隔符,其中有2条异常数据,一条数据是只有2个字段,一条数据是有4个字段。其内容如下所示:

jim   1   28

kate  0   26

tom  1

lily   0   29  22

编写代码统计文档中字段不为3个的异常数据个数。如果字段超过3个视为过长字段,字段少于3个视为过短字段。

2、编写程序代码:

package mr ;
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,
				org.apache.hadoop.mapreduce.Mapper<LongWritable, Text, Text, Text>.Context context)
				throws java.io.IOException, InterruptedException {
    
    
			String arr_value[] = value.toString().split("\t");
if (arr_value.length < 3) {
    
    
	ct = context.getCounter("ErrorCounter", "toolong"); // 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.setJarByClass(Counters.class); 
		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);
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iGZJp3e5-1592059114867)()]

3、打包并提交

使用Eclipse开发工具将该代码打包,选择主类为mr.Counters。假定打包后的文件名为Counters.jar,主类Counters位于包mr下,则可使用如下命令向Hadoop集群提交本应用。

[root@master hadoop]# bin/hadoop jar Counters.jar mr.Counters /usr/counters/in/counters.txt /usr/counters/out

其中“hadoop”为命令,“jar”为命令参数,后面紧跟打包。 “/usr/counts/in/counts.txt”为输入文件在HDFS中的位置(如果没有,自行上传),“/usr/counts/out”为输出文件在HDFS中的位置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9bEZ8xF-1592059114869)()]

4、实验操作:

步骤1 首先在Hadoop下使用 sbin/start-all.sh 命令启动集群。

步骤2 上传数据文件至HDFS

因为没有HDFS中没有 /usr/counters/in/ 目录,所以要先创建数据输入的路径。之后将放在/root/data/7/counters.txt的数据文件上传到刚刚创建好的路径

步骤3编写计数器程序。

步骤4打包程序。

步骤5 运行程序。

猜你喜欢

转载自blog.csdn.net/weixin_44322234/article/details/106739463