一、全排序
1.全排序也就是全局排序,意为多区间上的全局排序。
2.这是相对单区间单Reducer任务排序而发展出来的多区间多Reducer任务的排序。可以提高程序的并行性,提升效率。
3.多区间的排序时间受限于最长排序时间的那个区间,所以为使总体排序时间最短,就要求数据在各区间的分布相对均匀。可以采用Hadoop默认的抽样器先对数据抽样,根据数据的分布生成分区文件,这样能有效避免数据倾斜导致的性能降低。
4.如下图,分别为:单Reducer任务排序和多Reducer任务排序的示意图
5.上篇博文《MapReduce编程之二次排序》中的第四种排序方式,即是全排序的实现。只是采用的自定义分区没有考虑数据的分布情况,存在数据倾斜的问题。
二、全排序(抽样)代码实现
1.驱动类
(注:Mapper类和Reducer类采用Hadoop默认提供的)
package com.hadoop.mr.totalsort;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.partition.InputSampler;
import org.apache.hadoop.mapreduce.lib.partition.InputSampler.RandomSampler;
import org.apache.hadoop.mapreduce.lib.partition.TotalOrderPartitioner;
public class MR_TotalSort {
public static void main(String[] args) throws Exception{
//设置数据读入、输出路径
Path inputPath = new Path(args[0]);
Path outputPath = new Path(args[1]);
//设置分区文件路径
Path partitionFile = new Path(args[2]);
//设置reduce任务数
int numReduceTasks = Integer.parseInt(args[3]);
//设置样本数据抽样
//RandomSampler第一个参数表示会被选中的概率
//第二个参数表示选取的样本数
//第三个参数表示最大读取InputSplit数
RandomSampler<Text, Text> sampler = new InputSampler.RandomSampler<Text, Text>(0.1, 10, 1);
//加载hadoop配置信息
Configuration conf = new Configuration();
//设置作业的分区文件路径
TotalOrderPartitioner.setPartitionFile(conf, partitionFile);
//初始化作业信息
Job job = Job.getInstance(conf, "MR_TotalSort");
job.setJarByClass(MR_TotalSort.class);
//设置文件数据输入类型(或者称读入方式)
//KeyValueTextInputFormat类,会将文件的每一行默认按第一个制表符'\t'分割为key/value对(都是Text类型)
//若制表符不存在,则将整行作为key,value置为null
job.setInputFormatClass(KeyValueTextInputFormat.class);
//不需要设置Mapper和Reducer类,使用默认的
//设置Mapper输出键值对类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//设置reduce任务个数
job.setNumReduceTasks(numReduceTasks);
//设置分区类
job.setPartitionerClass(TotalOrderPartitioner.class);
//设置文件输入/输出路径
FileInputFormat.addInputPath(job, inputPath);
FileSystem fs = outputPath.getFileSystem(conf);
if (fs.exists(outputPath)) {
//删除输出路径,递归删除子目录文件
fs.delete(outputPath, true);
}
FileOutputFormat.setOutputPath(job, outputPath);
//写入分区文件(需要读取输入文件)
InputSampler.writePartitionFile(job, sampler);
//提交作业
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
三、打包Jar,运行程序
1.将com.hadoop.mr.totalsort包右键导出为 JAR file,命名为:"MR_TotalSort.jar";
2.利用Windows的cmd或者PowerShell(推荐)将JAR文件上传到Linux服务器
命令如下:(在JAR文件目录下执行)
> scp MR_TotalSort.jar root@remoteIP:~/myJars/mapreduce/
(其中remoteIP为远程服务器IP)
3.启动hadoop
--创建待排序输入文件
> cd ~/myJars/mapreduce/
> touch sortdata
> vi sortdata
按键"i",进入编辑模式,向sortdata文件中输入内容,如下:
(注:此处每行的数据分隔符是空格,不是制表符'\t',因此数据读入方式是整行作为key,value置null)
4 2
4 3
4 1
3 4
2 7
2 3
1 7
3 9
3 5
1 5
0 5
6 4
6 8
6 3
7 6
10 4
11 2
55 5
按键"ESC"-->"shift q"-->输入"wq!",回车,保存
--查看文件
> cat sortdata
--在HDFS中创建输入文件目录
> hadoop fs -mkdir /user/hadoop/totalsortinput
--在HDFS中查看输入文件目录
> hadoop fs -ls /user/hadoop/totalsortinput
--将本地的两个文件拷贝到HDFS的输入目录中(在"~/myJars/mapreduce/"下执行)
--可以多个文件一起传输
> hadoop fs -copyFromLocal sortdata /user/hadoop/totalsortinput/
4.执行JAR,运行程序
命令如下:(在JAR文件目录"~/myJars/mapreduce/"下执行)
> hadoop jar MR_TotalSort.jar com.hadoop.mr.totalsort.MR_TotalSort /user/hadoop/totalsortinput /user/hadoop/totalsortoutput /user/hadoop/totalsortpartition 3
运行过程中,屏幕会输出执行过程,直到完成
5.查看分区结果文件
> hadoop fs -text /user/hadoop/totalsortpartition
11 2 (null)
4 3 (null)
<即:按照'11 2'和'4 3'两个数据进行分区划分界线,并且排序规则为MR默认的字符串大小比较>
6.查看全排序结果
--设置的Reducer任务数为3:
成功执行完后,目录"/user/hadoop/totalsortoutput/"下会产生四个文件
/user/hadoop/totalsortoutput/_SUCCESS --成功执行完的空标识文件
/user/hadoop/totalsortoutput/part-r-00000 --作业输出结果文件(分区一)
/user/hadoop/totalsortoutput/part-r-00001 --作业输出结果文件(分区二)
/user/hadoop/totalsortoutput/part-r-00002 --作业输出结果文件(分区三)
--查看输出文件(采用MR默认的字符串大小比较,并非自定义的数值排序)
> hadoop fs -cat /user/hadoop/totalsortoutput/part-r-00000
0 5
1 5
1 7
10 4
> hadoop fs -cat /user/hadoop/totalsortoutput/part-r-00001
11 2
2 3
2 7
3 4
3 5
3 9
4 1
4 2
> hadoop fs -cat /user/hadoop/totalsortoutput/part-r-00002
4 3
55 5
6 3
6 4
6 8
7 6