Hadoop之MapReduce-自定义排序编程

一、问题描述

        根据给出的数据计算每一个账户总的收入,总的支出以及总利润,并按照总利润由高到低排序,如果总利润相同,则按照总的支出由低到高排序。

二、数据格式

       2.1输入数据格式
       zhangsan@163.com    6000    0    2014-02-20
       zhangsan@163.com    0    1000    2014-02-20
       lisi@163.com    2000    1000    2014-02-20
       lisi@163.com    10000    9000    2014-02-20
       beibei@126.com    100    0    2014-02-20
       wangwu@163.com    6000    2000    2014-02-20

       2.2输出数据格式 
       zhangsan@163.com    6000.0    1000.0    5000.0
       wangwu@163.com    6000.0    2000.0    4000.0
       lisi@163.com    12000.0    10000.0    2000.0
       beibei@126.com    100.0    0.0    100.0

三、问题实现

        第一步:将每个账户的总的收入,总的支出以及总利润计算输出到HDFS。【默认按照数据字典排序】

        第二步:将输出的结果自定义排序。

        类InforBean

package edu.jianwei.hadoop.mr.sort;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.WritableComparable;

public class InfoBean implements WritableComparable<InfoBean> {

	private String account;

	private double income;

	private double expenses;

	private double profit;

	public void set(String account, double income, double expenses) {
		this.account = account;
		this.income = income;
		this.expenses = expenses;
		this.profit = income - expenses;
	}

	@Override
	public String toString() {
		return this.income + "\t" + this.expenses + "\t" + this.profit;
	}

	/**
	 * serialize
	 */
	public void write(DataOutput out) throws IOException {
		out.writeUTF(account);
		out.writeDouble(income);
		out.writeDouble(expenses);
		out.writeDouble(profit);
	}

	/**
	 * deserialize
	 */
	public void readFields(DataInput in) throws IOException {
		this.account = in.readUTF();
		this.income = in.readDouble();
		this.expenses = in.readDouble();
		this.profit = in.readDouble();
	}

	public int compareTo(InfoBean o) {
        if (this.profit == o.getProfit()) {
            return this.expenses > o.getExpenses() ? 1 : -1;
        } else {
            return this.profit > o.getProfit() ? -1 : 1;
        }
        }

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}

	public double getIncome() {
		return income;
	}

	public void setIncome(double income) {
		this.income = income;
	}

	public double getExpenses() {
		return expenses;
	}

	public void setExpenses(double expenses) {
		this.expenses = expenses;
	}

	public double getProfit() {
		return profit;
	}

	public void setProfit(double profit) {
		this.profit = profit;
	}

}

         类SumStep:
package edu.jianwei.hadoop.mr.sort;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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;

public class SumStep {
	static class SumMapper extends Mapper<LongWritable, Text, Text, InfoBean> {
		public Text k = new Text();
		public InfoBean v = new InfoBean();

		@Override
		protected void map(LongWritable key, Text value, Context context)
				throws IOException, InterruptedException {
			String line = value.toString();
			String[] str = line.split("\t");
			String account = str[0];
			double income = Double.parseDouble(str[1]);
			double expenses = Double.parseDouble(str[2]);
			k.set(account);
			v.set(account, income, expenses);
			context.write(k, v);
		}

	}

	static class SumReducer extends Reducer<Text, InfoBean, Text, InfoBean> {

		public InfoBean v = new InfoBean();

		@Override
		protected void reduce(Text key, Iterable<InfoBean> values,
				Context context) throws IOException, InterruptedException {
			double total_inclome = 0;
			double total_expenses = 0;
			for (InfoBean v : values) {
				total_inclome += v.getIncome();
				total_expenses += v.getExpenses();
			}
			v.set(null, total_inclome, total_expenses);
			context.write(key, v);
		}
	}

	public static void main(String[] args) throws IllegalArgumentException,
			IOException, InterruptedException, ClassNotFoundException {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);

		job.setJarByClass(SumStep.class);

		job.setMapperClass(SumMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(InfoBean.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));

		job.setReducerClass(SumReducer.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(InfoBean.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));

		job.waitForCompletion(true);
	}

}
        

        类SortStep:

package edu.jianwei.hadoop.mr.sort;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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;

public class SortStep {

	public static void main(String[] args) throws IOException,
			InterruptedException, ClassNotFoundException {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);

		job.setJarByClass(SortStep.class);

		job.setMapperClass(SortMapper.class);
		job.setMapOutputKeyClass(InfoBean.class);
		job.setMapOutputValueClass(NullWritable.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));

		job.setReducerClass(SortReducer.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(InfoBean.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));

		job.waitForCompletion(true);
	}

	public static class SortMapper extends
			Mapper<LongWritable, Text, InfoBean, NullWritable> {
		public InfoBean k = new InfoBean();

		@Override
		protected void map(LongWritable key, Text value, Context context)
				throws IOException, InterruptedException {
			String line = value.toString();
			String[] strs = line.split("\t");
			String account = strs[0];
			double income = Double.parseDouble(strs[1]);
			double expenses = Double.parseDouble(strs[2]);
			k.set(account, income, expenses);
			context.write(k, NullWritable.get());
		}
	}

	public static class SortReducer extends
			Reducer<InfoBean, NullWritable, Text, InfoBean> {
		public Text k = new Text();

		@Override
		protected void reduce(InfoBean bean, Iterable<NullWritable> v2s,
				Context context) throws IOException, InterruptedException {
			String account = bean.getAccount();
			k.set(account);
			context.write(k, bean);
		}

	}

}

四、输出结果

        第一步:将每个账户的总的收入,总的支出以及总利润计算输出到HDFS。     

        1.代码运行 

          hadoop jar /root/sort.jar edu.jianwei.hadoop.mr.sort.SumStep /sort  /sort/sum

        2.输出结果

        beibei@126.com    100.0    0.0    100.0
        lisi@163.com    12000.0    10000.0    2000.0
        wangwu@163.com    6000.0    2000.0    4000.0
        zhangsan@163.com    6000.0    1000.0    5000.0

        第二步:将输出的结果自定义排序。

       1.代码运行 

         hadoop jar /root/sort.jar edu.jianwei.hadoop.mr.sort.SortStep /sort/sum  /sort/sortRes、

        2.输出结果

        zhangsan@163.com    6000.0    1000.0    5000.0
        wangwu@163.com    6000.0    2000.0    4000.0
        lisi@163.com    12000.0    10000.0    2000.0
        beibei@126.com    100.0    0.0    100.0






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MapReduce是一种用于处理大规模数据集的编程模型和软件框架。Hadoop是一个基于MapReduce模型的分布式文件存储和处理系统。在Hadoop中,MapReduce被广泛用于数据处理和分析任务。 自定义二次排序MapReduce中常见的一种需求,其目的是对MapReduce的输出进行排序。下面我们来介绍一下如何在Linux上使用Hadoop实现自定义二次排序。 1. 准备数据 首先我们需要准备一个数据集,假设我们有一个文本文件,每行包含两个字段,分别为学生姓名和成绩,中间用制表符分隔。例如: ``` Tom 80 Jerry 70 Mike 90 Lucy 85 ``` 2. 编写Mapper代码 自定义二次排序需要进行两次排序,第一次按照学生姓名进行排序,第二次按照成绩进行排序。因此,我们需要在Mapper中将学生姓名和成绩作为Key-Value输出。 我们可以使用TextPair类来存储学生姓名和成绩,代码如下: ``` public class SortMapper extends Mapper<LongWritable, Text, TextPair, Text> { private TextPair pair = new TextPair(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] fields = value.toString().split("\t"); pair.set(fields[0], fields[1]); context.write(pair, value); } } ``` 在这段代码中,我们首先将输入的一行数据拆分成学生姓名和成绩两个字段,然后使用TextPair类将它们作为Key输出,原始数据作为Value输出。 3. 编写Partitioner代码 Partitioner用于对Mapper的输出进行分区,以确保相同Key的数据被分配到同一个Reducer中。在自定义二次排序中,我们需要按照学生姓名进行分区,因此我们可以使用HashPartitioner来进行分区,代码如下: ``` public class SortPartitioner extends Partitioner<TextPair, Text> { public int getPartition(TextPair key, Text value, int numPartitions) { return (key.getFirst().hashCode() & Integer.MAX_VALUE) % numPartitions; } } ``` 在这段代码中,我们使用HashPartitioner将学生姓名的HashCode和Partition数取模来确定数据被分配到哪个Reducer中。 4. 编写GroupComparator代码 GroupComparator用于将相同学生姓名的数据分配到同一个Reducer中,代码如下: ``` public class SortGroupComparator extends WritableComparator { protected SortGroupComparator() { super(TextPair.class, true); } public int compare(WritableComparable a, WritableComparable b) { TextPair pair1 = (TextPair) a; TextPair pair2 = (TextPair) b; return pair1.getFirst().compareTo(pair2.getFirst()); } } ``` 在这段代码中,我们重载了compare方法,用于比较两个Key的学生姓名是否相同。 5. 编写SortComparator代码 SortComparator用于对每个Reducer中的数据进行排序,按照成绩从大到小排序,代码如下: ``` public class SortComparator extends WritableComparator { protected SortComparator() { super(TextPair.class, true); } public int compare(WritableComparable a, WritableComparable b) { TextPair pair1 = (TextPair) a; TextPair pair2 = (TextPair) b; int cmp = pair1.getFirst().compareTo(pair2.getFirst()); if (cmp != 0) { return cmp; } return -pair1.getSecond().compareTo(pair2.getSecond()); } } ``` 在这段代码中,我们首先比较两个Key的学生姓名是否相同,如果相同则比较成绩,否则直接返回姓名比较结果。 6. 编写Reducer代码 Reducer用于对Mapper的输出进行聚合和处理。在自定义二次排序中,我们只需要将每个学生的成绩按照从高到低的顺序输出即可,代码如下: ``` public class SortReducer extends Reducer<TextPair, Text, Text, Text> { public void reduce(TextPair key, Iterable<Text> values, Context context) throws IOException, InterruptedException { for (Text value : values) { context.write(key.getFirst(), value); } } } ``` 在这段代码中,我们首先输出学生姓名,然后按照原始数据的顺序输出。 7. 编写Driver代码 最后,我们需要编写Driver代码来启动MapReduce作业。代码如下: ``` public class SortDriver extends Configured implements Tool { public int run(String[] args) throws Exception { Job job = Job.getInstance(getConf()); job.setJarByClass(SortDriver.class); job.setMapperClass(SortMapper.class); job.setPartitionerClass(SortPartitioner.class); job.setGroupingComparatorClass(SortGroupComparator.class); job.setSortComparatorClass(SortComparator.class); job.setReducerClass(SortReducer.class); job.setMapOutputKeyClass(TextPair.class); job.setMapOutputValueClass(Text.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); return job.waitForCompletion(true) ? 0 : 1; } public static void main(String[] args) throws Exception { int exitCode = ToolRunner.run(new SortDriver(), args); System.exit(exitCode); } } ``` 在这段代码中,我们首先创建一个Job实例,然后设置Mapper、Partitioner、GroupComparator、SortComparator和Reducer等类。最后,我们指定输入路径和输出路径,并启动作业。 以上就是在Linux上使用Hadoop实现自定义二次排序的流程。通过这个例子,您可以了解到如何在Linux系统上使用MapReduce编程模型和Hadoop分布式文件存储和处理系统来处理大规模数据集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值