数据格式:
10,3333,10,100
11,9321,1000,293
12,3881,701,20
13,6974,910,30
14,8888,11,39
订单ID 用户ID 资费 业务ID
在所有订单数据中计算出资费最高的N个订单,按降序排列
算法思想:在大量的数据中计算出资费最高的N个订单,为了节省资源和提高计算效率:在众多的Mapper的端,首先计算出自己的TopN,然后在将每一个Mapper端的TopN汇总到Reducer端进行计算最终的TopN,这样就可以最大化的提高运行并行处理的能力,通时极大的减少网络的Shuffle传输数据,从而极大的加快的整个处理的效率;
代码示例
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.Text;
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;
import java.io.IOException;
import java.util.Arrays;
/**
* FileName: SortedTopN
* Author: hadoop
* Email: 3165845957@qq.com
* Date: 18-10-6 下午7:50
* Description:
*/
public class SortedTopN {
/**
* 使用Mapper将数据文件中的数据本身作为Mapper输出的key直接输出
*/
public static class SortedTopNMapper extends Mapper<LongWritable, Text, Text, Text> {
int[] topN;//存放TopN的数组
int length; //存放TopN的个数
//初始化
@Override
protected void setup(Context context) throws IOException, InterruptedException {
length = context.getConfiguration().getInt("topn",5); //获取输入的TopN的长度
topN = new int[length+1]; //初始化TopN数组,TopN[0]存储当前订单的金额
}
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] data = value.toString().split(","); //数据格式为8,1818,9000,20,按“,“进行切分
if (4 == data.length){ //符合格式的数据才进行处理
int cost = Integer.valueOf(data[2]); //获取订单的消费金额
topN[0] = cost; //TopN[0]存储最小的消费金额
Arrays.sort(topN); //对TopN进行生序排序
}
}
//结束的时候销毁
@Override
protected void cleanup(Context context) throws IOException, InterruptedException {
for (int i = 1; i < length+1;i++){ //统计出每一个Mapper的TopN金额
context.write(new Text(String.valueOf(topN[i])),new Text(String.valueOf(topN[i])));
}
}
}
/**
* 使用Reducer将输入的key本身作为key直接输出
*/
public static class SortedTopNReducer extends Reducer<Text, Text, Text, Text> {
int[] topN; //Reducer端的TopN数组,存放最终的TopN
int length; //最终的Reducer的TopN的长度
@Override
protected void setup(Context context) throws IOException, InterruptedException {
length = context.getConfiguration().getInt("topn",5); // 接受用户输入的指定TopN长度
topN = new int[length+1]; //初始化TopN数组,TopN[0]存储当前订单的金额
}
@Override
protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
topN[0] = Integer.valueOf(key.toString()); //获取每次Mapper进来的TopN,在所有Mapper的TopN中找出最大值的TopN
Arrays.sort(topN); //对TopN进行升序排序
}
@Override
protected void cleanup(Context context) throws IOException, InterruptedException {
for (int i = length; i > 0;i--){//截取最大的TopN
context.write(new Text(String.valueOf(length-i +1)),new Text(String.valueOf(topN[i])));
}
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();//设置MapReduce的配置
conf.setInt("topn",3);
String[] otherArgs = new GenericOptionsParser(conf,args).getRemainingArgs();
if(otherArgs.length < 2){
System.out.println("Usage: SortedTopN <in> [<in>...] <out>");
System.exit(2);
}
//设置作业
//Job job = new Job(conf);
Job job = Job.getInstance(conf);
job.setJarByClass(SortedTopN.class);
job.setJobName("SortedTopN");
//设置处理map,reduce的类
job.setMapperClass(SortedTopNMapper.class);
job.setReducerClass(SortedTopNReducer.class);
//设置输入输出格式的处理
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//设定输入输出路径
for (int i = 0; i < otherArgs.length-1;++i){
FileInputFormat.addInputPath(job,new Path(otherArgs[i]));
}
FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length-1]));
System.exit(job.waitForCompletion(true)?0:1);
}
}