使用Partitioner实现输出到多个文件

1、需求

  按学生的年龄段,将数据输出到不同的文件。这里我们分为三个年龄段:小于等于20岁、大于20岁小于等于50岁和大于50岁

2、实现

  1、编写Partitioner,代码如下

public static class StudentPartitioner extends Partitioner<IntWritable, Text> {
	@Override
	public int getPartition(IntWritable key, Text value, int numReduceTasks) {
		// 学生年龄
		int ageInt = key.get();
		
		// 默认指定分区 0
		if (numReduceTasks == 0)
			return 0;
	
		if (ageInt <= 20) { // 年龄小于等于20,指定分区0
			return 0;
		}else if (ageInt <= 50) { // 年龄大于20,小于等于50,指定分区1
			return 1;
		}else{ // 剩余年龄,指定分区2
			return 2;
		}
	}
}

  2、编写mapper

public static class StudentMapper extends Mapper<LongWritable, Text, IntWritable, Text>{
	@Override
	protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
		String[] studentArr = value.toString().split("\t");
		
		if(StringUtils.isNotBlank(studentArr[1])){
			/*
			 * 姓名	年龄(中间以tab分割)
			 * 张明明	45
			 */
			// 年龄
			IntWritable pKey = new IntWritable(Integer.parseInt(studentArr[1].trim()));
			
			// 以年龄作为key输出
			context.write(pKey, value);
		}
	}
}

  3、编写reducer

public static class StudentReducer extends Reducer<IntWritable, Text, NullWritable, Text> {
	@Override
	protected void reduce(IntWritable key, Iterable<Text> values,Context context) throws IOException, InterruptedException {
		for(Text value : values){
			context.write(NullWritable.get(), value);
		}
	}
}

  4、一些运行代码

@Override
public int run(String[] arg0) throws Exception {
	// 读取配置文件
	Configuration conf = new Configuration();
	
	Path mypath = new Path(arg0[1]);
	FileSystem hdfs = mypath.getFileSystem(conf);
	if (hdfs.isDirectory(mypath)) {
		hdfs.delete(mypath, true);
	}
	
	// 新建一个任务
	Job job = new Job(conf, "PartitionerDemo");
	// 设置主类
	job.setJarByClass(StudentPartitioner.class);
	
	// 输入路径
	FileInputFormat.addInputPath(job, new Path(arg0[0]));
	// 输出路径
	FileOutputFormat.setOutputPath(job, new Path(arg0[1]));
	
	// Mapper
	job.setMapperClass(StudentMapper.class);
	// Reducer
	job.setReducerClass(StudentReducer.class);
	
	// mapper输出格式
	job.setMapOutputKeyClass(IntWritable.class);
	job.setMapOutputValueClass(Text.class);
	
	// reducer输出格式
	job.setOutputKeyClass(NullWritable.class);  
        job.setOutputValueClass(Text.class); 
        
        //设置Partitioner类
        job.setPartitionerClass(StudentPartitioner.class);
        // reduce个数设置为3
	job.setNumReduceTasks(3);
	
	//提交任务
	return job.waitForCompletion(true)?0:1;
}
public static void main(String[] args0) throws Exception {
	// 数据输入路径和输出路径
//	String[] args0 = {
//		"hdfs://ljc:9000/buaa/student/student.txt",
//		"hdfs://ljc:9000/buaa/student/out/"
//	};
	int ec = ToolRunner.run(new Configuration(), new StudentAgePartitionerDemo(), args0);
	System.exit(ec);
}

3、总结

  Partitioner适用于事先知道分区数的情况下,比如像上面这个需求

  缺点:

    1、在作业运行之前需要知道分区数,也就是年龄段的个数,如果分区数未知,就无法操作。

    2、一般来说,让应用程序来严格限定分区数并不好,因为可能导致分区数少或分区不均

本文版权归作者和csdn共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

实现代码及数据:下载

你可能感兴趣的:(mapreduce,Partitioner,输出多个文件,输出多个文件)