MapReduce案例排序2 ,利用MapReduce自身排序功能排序
需求:
统计request.dat中每个页面被访问的总次数,同时,要求输出结果文件中的数据按照次数大小倒序排序
关键技术点:
- mapreduce程序内置了一个排序机制,所以如果需要排序,可设置一个bean对象,然后利用Comparable<>接口,对其进行排序。
- map worker 和reduce worker ,都会对数据按照key的大小来排序。
- 如果对象需要实现可序列化接口,又需要实现Comparable<>接口,则这个java对象可以实现WritableComparable接口。
思路:
本案例中,就可以利用这个机制来实现需求:
1、先写一个mr程序,将每个页面的访问总次数统计出来。常规的计词。
2、再写第二个mr程序:
- map阶段: 读取第一个mr产生的结果文件,将每一条数据解析成一个java对象UrlCountBean(封装着一个url和它的总次数),然后将这个对象作为key,null作为value返回,设置Comparable<>接口。
- reduce阶段:由于worker已经对收到的数据按照UrlCountBean的compareTo方法排了序,所以,在reduce方法中,只要将数据输出即可,最后的结果自然是按总次数大小的有序结果
流程图
代码
Bean对象的创建
java对象UrlCountBean实现可序列化接口和comparetable<>。
public class PageCount implementsWritableComparable<PageCount>{
private String page;
private int count;
public void set(String page,int count){
this.page=page;
this.count=count;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int compareTo(PageCount o) { //比较原则
return o.getCount()-this.count==0?this.page.compareTo(o.getPage()):o.getCount()-this.count;
}
public void readFields(DataInput in) throws IOException { //反序列化
this.count=in.readInt();
this.page=in.readUTF();
}
public void write(DataOutput out) throws IOException { //序列化
out.writeInt(count);
out.writeUTF(page);
}
}
第一次MapReduce
功能:就普普通通的切词。
public class PageCountStep1{
public static class PageCountStep1Mapper extends Mapper<LongWritable, Text, Text, IntWritable>
{
@Override
protected void map(LongWritable key, Text value,
Context context)throws IOException, InterruptedException {
String line =value.toString();
String[] split=line.split(" ");
context.write(new Text(split[1]), new IntWritable(1));
}
}
public static class PageCountStep1Reducer extends Reducer<Text, IntWritable, Text, IntWritable>{
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context)
throws IOException, InterruptedException {
int count=0;
for(IntWritable value:values){
count+=value.get();
}
context.write(key, new IntWritable(count));
}
}
public static void main(String[] args) throws Exception {
Configuration conf =new Configuration();
conf.set("fs.defaultFS", "file:///");
conf.set("mapreduce.framework.name","local");
Job job=Job.getInstance(conf);
//1、封装参数:jar包所在的位置
job.setJarByClass(JobSumbmitterWindowsLocal.class);
// 2、封装参数: 本次job所要调用的Mapper实现类、Reducer实现类
job.setMapperClass(PageCountStep1Mapper.class);
job.setReducerClass(PageCountStep1Reducer.class);
//3、封装参数:本次job的Mapper实现类、Reducer实现类产生的结果数据的key、value类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//4、封装参数:本次job要处理的输入数据集所在路径、最终结果的输出路径
FileInputFormat.setInputPaths(job, new Path("e:/HadoopText/WordCountInput"));
FileOutputFormat.setOutputPath(job, new Path("e:/HadoopText/WordCountOutput")); // 注意:输出路径必须不存在
job.setNumReduceTasks(3);
//6、提交job给yarn
boolean res = job.waitForCompletion(true);
}
}
第二次MapReduce
- map阶段: 读取第一个mr产生的结果文件,将每一条数据解析成一个java对象UrlCountBean(封装着一个url和它的总次数),然后将这个对象作为key,null作为value返回,设置Comparable<>接口。
- reduce阶段:由于worker已经对收到的数据按照UrlCountBean的compareTo方法排了序,所以,在reduce方法中,只要将数据输出即可,最后的结果自然是按总次数大小的有序结果
public class PageCountStep2 {
public static class PageCountStep2Mapper extends Mapper<LongWritable, Text,PageCount,NullWritable>{
@Override
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {
String[] split=value.toString().split("/t"); //解析数据
PageCount pagecount=new PageCount();
pagecount.set(split[0], Integer.parseInt(split[1])); //封装入Context对象中
context.write(pagecount, NullWritable.get());
}
public static class PageCountStep2Reducer extends Reducer<PageCount,NullWritable,PageCount,NullWritable>{
@Override
protected void reduce(PageCount key, Iterable<NullWritable> values,
Context context)
throws IOException, InterruptedException {
context.write(key, NullWritable.get());
}
public static void main(String[] args) throws Exception {
Configuration conf =new Configuration();
conf.set("fs.defaultFS", "file:///");
conf.set("mapreduce.framework.name","local");
Job job=Job.getInstance(conf);
//1、封装参数:jar包所在的位置
job.setJarByClass(JobSumbmitterWindowsLocal.class);
// 2、封装参数: 本次job所要调用的Mapper实现类、Reducer实现类
job.setMapperClass(PageCountStep2Mapper.class);
job.setReducerClass(PageCountStep2Reducer.class);
//3、封装参数:本次job的Mapper实现类、Reducer实现类产生的结果数据的key、value类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//4、封装参数:本次job要处理的输入数据集所在路径、最终结果的输出路径
FileInputFormat.setInputPaths(job, new Path("e:/HadoopText/WordCountInput"));
FileOutputFormat.setOutputPath(job, new Path("e:/HadoopText/WordCountOutput")); // 注意:输出路径必须不存在
job.setNumReduceTasks(11 ` );
//6、提交job给yarn
boolean res = job.waitForCompletion(true);
}