从零开始大数据【1.4】-- mapreduce中的排序+自定义WritableComparable

本文详细介绍了MapReduce中的排序机制,包括Map Task和Reduce Task的排序过程,并探讨了如何自定义排序方式。通过一个实际案例,展示了如何在Bean对象中实现WritableComparable接口以按照特定字段(如reviews数量)进行排序。文章还逐步解析了mapper、reducer和driver的编程过程,最终实现了按reviews数量降序输出的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从零开始大数据【1.4】-- mapreduce中的排序+自定义WritableComparable

1 上期回顾:

第二节中,我们定义了一个新的数据类型作为mapreduce中的数据类型,当时把这个数据类型当做value值,所以没有涉及到排序,现在我们准备将他作为key值,所以来写它的WritableComparable。

2 mapreduce中的排序

排序是 MapReduce 框架中最重要的操作之一。Map Task和 Reduce Task均会对数据(按照 key)进行排序。该操作属于 Hadoop 的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。默认排序是按照字典顺序排序,实现该排序的方法是快速排序。
对于 Map Task,它会将处理的结果暂时放到一个缓冲区中,当缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次排序,并将这些有序数据写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行一次合并,以将这些文件合并成一个大的有序文件。
对于 Reduce Task,它从每个 Map Task上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则放到磁盘上,否则放到内存中。如果磁盘上文件数目达到一定阈值,则进行一次合并以生成一个更大文件;如果内存中文件大小或者数目超过一定阈值,则进行一次合并后将数据写到磁盘上。当所有数据拷贝完毕后,Reduce Task 统一对内存和磁盘上的所有数 据进行一次合并。
可以看到,对key的排序多次出现在mapreduce程序中,接下来就来说怎么自定义排序的方式。

3 实际案例

仍然采用之前的数据集,这一次,希望输出的结果是按照reviews的数量排序输出的,为了完成这个目的,首先要在自定义的bean对象中添加WritableComparable。

4 编写bean对象

主要是变成implements WritableComparable并且重写了compareTo方法。

        package appmapreduce;
    
    import java.io.DataInput;
    import java.io.DataOutput;
    import java.io.IOException;
    
    import org.apache.hadoop.io.Writable;
    import org.apache.hadoop.io.WritableComparable;
    
    public class nbean implements WritableComparable<nbean>{
    	
    	private long reviews;	
    	private double rating;
    	
    	
    	//空参构造(在source中 generate construct using fields)
    	public nbean() {
    		super();
    	}

    	public nbean(long reviews,  double rating) {
    		super();
    		this.reviews = reviews;		
    		this.rating = rating;	
    	}
    
    	@Override
    	public String toString() {
    		return reviews +"\t"+rating;
    	}
    
    	//反序列化方法
    	@Override
    	public void readFields(DataInput in) throws IOException {
    		// TODO Auto-generated method stub

    		this.rating = in.readLong();
    		this.reviews = in.readLong();
    		
    		
    	}
    	//序列化方法
    	@Override
    	public void write(DataOutput out) throws IOException {
    		// TODO Auto-generated method stub
    		
    		 out.writeDouble(rating);
    		 out.writeLong(reviews);
    		 
    	}
    
       	
    	public long getReviews() {
    		return reviews;
    	}
    
    	public void setReviews(long reviews) {
    		this.reviews = reviews;
    	}
     
    	public double getRating() {
    		return rating;
    	}
        
    	public void setRating(double rating) {
    		this.rating = rating;
    	}
    
    	public void set(long reviews,double rating) {	
    		this.reviews = reviews;
    		this.rating = rating;	
    	}
    	@Override
    	public int compareTo(nbean o) {
    		// TODO Auto-generated method stub
    		return (int)(this.reviews-o.getReviews());	
    	}
     
    }

5 mapreduce编程

要完成上述的例子,同样需要完成三个程序分别是一个mapper类、一个reducer类和一个用于连接整个过程的驱动driver主程序。

5.1 mapper

新建的mapper类基本不变只改变了输出的数据类型。

    package appmapreduce;
    import java.io.IOException;
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    public class appmapper extends Mapper<LongWritable, Text, nbean, Text>{
    	
    	nbean vall = new nbean();
    	Text kl = new Text();
    	@Override
    	protected void map(LongWritable key, Text value,Context context)
    			throws IOException, InterruptedException {
    		// TODO Auto-generated method stub
    	
    		//获取一行
    		String line = value.toString();
    		//切割
    		String[] fields = line.split("\t");
    		System.out.println(fields);
    		//封装
    		
    		String category = fields[1];
    		double rating = Double.parseDouble(fields[2]);
    		long reviews = Long.parseLong(fields[3]);
    		
    		vall.set(reviews, rating);
    		kl.set(category);
    
    		//写出数据
    		context.write(vall, kl);
    		
    	}
    }

5.2 reducer

建立 reducer继承reducer类,重写reduce函数,这里的reducer只是把kv调换后输出。

    package appmapreduce;
    import java.io.IOException;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    public class appreducer extends Reducer<nbean, Text, Text, nbean>{
    	@Override
    	protected void reduce(nbean key, Iterable<Text> values, Context context)
    			throws IOException, InterruptedException {
    		// TODO Auto-generated method stub
    		/*double avgrating =  0;
    		long sumreviews =  0;
    		int count = 0;
    		
    		//累加求和,累加求平均
    		for (nbean nbean : values) {
    			sumreviews = nbean.getReviews();
    			avgrating = nbean.getRating();	
    			count +=1;
    		}
    		
    		
    		nbean newval = new nbean(sumreviews,avgrating);
    		//输出
    		 * */
    		 
    		context.write(values.iterator().next(),key);
		}

    }

5.3 driver

只是更改了map的输出类型

        package appmapreduce;
    import java.io.IOException;
    import org.apache.hadoop.conf.Configuration;
    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.output.FileOutputFormat;
    
    public class appdriver {
    	public static void main(String[] args) throws IllegalArgumentException, IOException, ClassNotFoundException, InterruptedException {
    		
    		//1 获取job对象
    		Configuration configuration = new Configuration();
    		Job job = Job.getInstance(configuration);
    		
    		//2 设置jar路径
    		job.setJarByClass(appdriver.class);
    		//3 mapper reducer类
    		job.setMapperClass(appmapper.class);
    		job.setReducerClass(appreducer.class);
    		
    		//4 mapper kv
    		job.setMapOutputKeyClass(nbean.class);
    		job.setMapOutputValueClass(Text.class);
    		
    		//5reducer kv
    		job.setOutputKeyClass(Text.class);
    		job.setOutputValueClass(nbean.class);
    		
    		
    		//8 分区
    		//job.setPartitionerClass(catpartitioner.class);
    		//job.setNumReduceTasks(2);
    		
    		//6 输入输出路径
    		FileInputFormat.setInputPaths(job, new Path("e:/tyr"));
    		FileOutputFormat.setOutputPath(job, new Path("e:/oo2"));
    		
    		//7 提交
    		
    		boolean result = job.waitForCompletion(true);
    		
    }
    }

5.4 运行

在这里插入图片描述
得到的输出结果如上图所示,可以发现自动按照reviews的重少到多排序了。

【欢迎大家和我一起学习!!!!】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值