一、全排序

1.全排序也就是全局排序,意为多区间上的全局排序。

2.这是相对单区间单Reducer任务排序而发展出来的多区间多Reducer任务的排序。可以提高程序的并行性,提升效率。

3.多区间的排序时间受限于最长排序时间的那个区间,所以为使总体排序时间最短,就要求数据在各区间的分布相对均匀。可以采用Hadoop默认的抽样器先对数据抽样,根据数据的分布生成分区文件,这样能有效避免数据倾斜导致的性能降低。

4.如下图,分别为:单Reducer任务排序和多Reducer任务排序的示意图

hadoop head 前一百行 hadoop全排序_apache

 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