【hadoop学习之路】MapReduce实现数字排序

参考视频:【狂野大数据】一天搞定大数据之MapReduce

目录

1. MapReduce 运行流程

2. 规划自定义的 MapReduceSort 程序

3. 代码实现

4. 问题解决


1. MapReduce 运行流程

MapReduce主要经过三个阶段:

① Map阶段

1)以格式读取文本文件,其中k1为文本偏移量,通常定义为数字类型(如LongWritable),v2为文本,通常定义为Text类型

2)自定义语句,用于处理及生成

3)将2)中生成的写入Context类的对象中

② Shuffle阶段

1)分区

2)排序

3)规约

4)分组

最后形成新的并输出

③ Reduce阶段

1)以形式读取数据

2)自定义语句,用于处理及生成

3)以形式输出数据

【hadoop学习之路】MapReduce实现数字排序_第1张图片

【hadoop学习之路】MapReduce实现数字排序_第2张图片

(图为自制,有参考视频内容)

2. 规划自定义的 MapReduceSort 程序

需求:

现有文件:

s1.txt:

35 12345 21 5 -8 365

s2.txt:

38 156 12 6 -2 -10

s3.txt:

45 2365 68 -15 -18 -30

运用MapReduce编写一个简单排序的程序,如果将上面三个文件作为输入,则排序后的输出结果如下所示:

1    -30

2    -18

3    -15

4    -10

5    -8

6    -2

7       5

8      6

9    12

10      21

11      35

12      38

13      45

14      68

15      156

16      365

17      2365

18      12345

解:

程序设计思路如下:

① Map阶段

1)以格式读取文本文件

2)分割文本,提取数字并写入S自定义的SortBean类型中

3)将2)中生成的写入Context类的对象中

② Shuffle阶段

1)分区:默认

2)排序:自定义SortBean类型,用于shuffle阶段的排序

3)规约:默认

4)分组:默认

最后形成新的并输出

③ Reduce阶段

1)以形式读取数据

2)从SortBean中提取数字,写入IntWritable

3)以形式输出数据

④ 执行阶段

1)将各个阶段写入Job类型的对象中

2)加入配置、输入输出格式、输入输出路径等

3)等待任务执行完成

3. 代码实现

实现代码如下:

package MapReduceSort;

import java.lang.System;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

//需求:同一个文件夹下的三个文件t1 t2 t3,输出三个文件合并后的排序值

public class MapReduceSort {
	
	// 定义自己的mapper类型
	// key in - LongWritable 行偏移量
	// value in - Text 以文本形式读取数字
	// key out - SortBean 以自定义比较器类型传入key,以便shuffle阶段实现排序
	// value out - NullWritable 不写入任何内容
	public static class MyMapper extends Mapper {
	
	@Override
		protected void map(LongWritable key, Text value,
				Mapper.Context context)
				throws IOException, InterruptedException {
		
		String[] split = value.toString().split(" ");
		
		for (String num: split) {
			SortBean sbnum = new SortBean();
			sbnum.setNum(Integer.parseInt(num));
			context.write(sbnum, NullWritable.get());
		}
	}
}
	// 实现比较器,制定排序原则
	public static class SortBean implements WritableComparable {
		
		private int num;
		
		public int getNum() {
			return num;
		}
		
		public void setNum(int num) {
			this.num = num;
		}
		
		// 实现反序列
		@Override
		public void readFields(DataInput in) throws IOException {
			this.num = in.readInt();
		}
		
		// 实现序列化
		@Override
		public void write(DataOutput out) throws IOException {
			out.writeInt(num);
		}

		// 实现排序:升序
		@Override
		public int compareTo(SortBean sortBean) {
			// 返回两数相减的值,即可排序
			// 若要实现降序,则将两数反过来做减法
			int result = this.num - sortBean.num ;
			return result;
		}
		
	}
	
	// key in - SortBean 接收mapper的key out,必须与mapper的key out类型保持相同
	// value in - NullWritable 接收mapper的value out,必须与mapper的value out类型保持相同
	// key out - IntWritable 数字必须以-Writable的形式写入输出文件,此处为整数的Writable
	// value out - NullWritable 不写入任何内容
	public static class MyReducer extends Reducer {

		@Override
		protected void reduce(SortBean key, Iterable values,
				Reducer.Context context)
				throws IOException, InterruptedException {
			// 写入输出文件中
			context.write(new IntWritable(key.getNum()), NullWritable.get());
		}
	}
	
	public static void main(String[] args) throws Exception 
	{
		Configuration conf = new Configuration();
		String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
		// 获取Run as -> Args 里面的两个参数
		// 如果没有2个参数,则会报以下错误,用户需要重新添加参数
		if (otherArgs.length != 2) {
			System.err.println("Usage: Need two configuration args!");
			System.exit(2);
		}
		
		@SuppressWarnings("deprecation")
		Job job = new Job(conf, "MapReduceSort"); // 新建一个job对象,第二个参数是job名字,可以随便取
		job.setJarByClass(MapReduceSort.class); // 写入总大类名称
		
		job.setMapperClass(MyMapper.class); //写入自定义的mapper类
		job.setMapOutputKeyClass(SortBean.class); // mapper类的key输出类型
		job.setMapOutputValueClass(NullWritable.class); // mapper类的value输出类型
		
		job.setReducerClass(MyReducer.class); //写入自定义的reducer类		
		job.setOutputKeyClass(IntWritable.class); // reducer类的key输出类型
		job.setOutputValueClass(NullWritable.class); // reducer类的value输出类型
		
		job.setInputFormatClass(TextInputFormat.class); 
		job.setOutputFormatClass(TextOutputFormat.class);
		
		//本地运行测试
		/*FileInputFormat.addInputPath(job, new Path("file:///D:\\Programming_files\\hadoop_local_test\\MapReduceSort\\files"));
		FileOutputFormat.setOutputPath(job, new Path("file:///D:\\Programming_files\\hadoop_local_test\\MapReduceSort\\results"));*/
		
        FileInputFormat.addInputPath(job, new Path(otherArgs[0])); // 输入路径为第一个参数
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); // 输出路径为第二个参数,该路径不能存在!
		
		System.exit(job.waitForCompletion(true) ? 0 : 1); // 等待任务执行完成
		
	}

}

运行结果:

【hadoop学习之路】MapReduce实现数字排序_第3张图片

4. 问题解决

1)org.apache.hadoop.security.AccessControlException: Permission denied: user=87029, access=WRITE

问题:hdfs的写入权限未开启

解决:在Xshell中使用如下指令放开写入权限

hadoop fs -chmod 777 /results # 放开文件路径为“/results”的写入权限

2)Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://master:9000/results/cd_sort already exists

问题:输出路径已经存在

解决:删除该文件夹

hadoop fs -rm -r /results/cd_sort # 删除路径为“/results/cd_sort”的文件夹

后记

本人为零基础小白,努力学习中,发布的文章难免有错误及纰漏之处,欢迎各位看官批评指正!

你可能感兴趣的:(hadoop学习之路,hadoop,大数据,mapreduce)