美国新冠疫情COVID-19
案例2:各州累计病例数呈倒排统计
将美国每个州state的确诊案例数进行倒序排序。
一、需求分析
如果你的需求中需要根据某个属性进行排序,不妨把这个属性作为key。因为MapReduce中key有默认排序行为的。可使用案例1的输出结果表作为本案例的输入表。
1、如果你的需求是正序,并且数据类型是Hadoop封装好的类型。这种情况下不需要任何修改,直接使用lHadoop类型作为kcy即可。因为Hadoop封装好的类型已经实现了排序规则。
2、如果你的需求是倒序,或者数据类型是自定义对象。需要重写排序规则。对象实现Comparable接口重写CompareTo方法。
把封装数据作为key,系统默认排序后,再把州和封装数据倒过来输出

二、代码实现
(一)CovidSortSumMapper
package mapreduce.CovidSortSum;
import beans.CovidCountBean2;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* Alabama 252900 3638
*/
public class CovidSortSumMapper extends Mapper<LongWritable, Text, CovidCountBean2, Text> {
/**
* 3、创建输出对象
*/
CovidCountBean2 outKey = new CovidCountBean2();
Text outValue = new Text();
/**
* 1、重写map父类方法:map回车
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
/**
* 2、读取一行数据进行切割
*/
String[] fields = value.toString().split("\t");
/**
* 4、提取数据 州、确诊数、死亡数
*/
outKey.set(Long.parseLong(fields[1]),Long.parseLong(fields[2]));
outValue.set(fields[0]);
/**
* 5、输出结果
*/
context.write(outKey,outValue);
}
}
注意LongWritable, Text, CovidCountBean2, Text,第二个是一条数据
(二)CovidSortSumReducer
package mapreduce.CovidSortSum;
import beans.CovidCountBean2;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class CovidSortSumReducer extends Reducer<CovidCountBean2, Text,Text,CovidCountBean2> {
@Override
protected void reduce(CovidCountBean2 key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
/**
* 排序好之后 reduce会进行分组操作,分组规则是判断key是否相等
* 本业务中,使用自定义对象作为key,并且没有重写分组规则,默认就会比较对象的地址,导致每个kv队就是一组
* <CovidCountBean2,加州> --------------><CovidCountBean2,Iterable[加州]>
* <CovidCountBean2,德州> --------------><CovidCountBean2,Iterable[德州]>
*/
Text outValues = values.iterator().next();
context.write(outValues,key);
}
}
(三)CovidSortSumDriver
package mapreduce.CovidSortSum;
import beans.CovidCountBean2;
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.output.FileOutputFormat;
/**
* 该类就是MapReduce程序客户端驱动类
* 主要是构造Job对象实例
* 指定各种组件属性:mapper、reducer类,输入输出的数据类型,输入输出的数据路径,提交job作业(job.submit())
*/
public class CovidSortSumDriver {
public static void main(String[] args) throws Exception {
//创建驱动类
Configuration conf = new Configuration();
//本地模式运行可以直接指定路径,或者配置Configurations
// args = new String[] {"F:/MyBigData/Hadoop/data/mr_wordcount/input ","F:/MyBigData/Hadoop/data/mr_wordcount/output"};
//设置mapreduce程序的运行模式
// conf.set("mapreduce.framework.name","local");
//构造job作业的实例,参数(配置对象,job名字)
Job job = Job.getInstance(conf, CovidSortSumDriver.class.getSimpleName());
//设置mr程序运行的主类
job.setJarByClass(CovidSortSumDriver.class);
//设置本次mr程序的mapper类型、reducer类型
job.setMapperClass(CovidSortSumMapper.class);
job.setReducerClass(CovidSortSumReducer.class);
//指定mapper阶段输出的key value数据类型
job.setMapOutputKeyClass(CovidCountBean2.class);
job.setMapOutputValueClass(Text.class);
//指定reducer阶段输出的key value数据类型,也是mr程序最终的输出数据类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(CovidCountBean2.class);
//配置本次作业的输入数据路径和输出数据路径
Path inputPath = new Path(args[0]);
Path outputPath = new Path(args[1]);
//todo 默认组件 TextInputFormat TextOutputFormat
FileInputFormat.setInputPaths(job, inputPath);
FileOutputFormat.setOutputPath(job,outputPath);
//todo 判断输出路径是否已经存在,如果已经存在,先删除
FileSystem fs = FileSystem.get(conf);
if(fs.exists(outputPath)){
fs.delete(outputPath,true); //递归删除
}
//最终提交本次job作业
//job.submit();
//采用waitForCompletion提交job,参数表示是否开启实时监视追踪作业的执行情况
boolean resultFlag = job.waitForCompletion(true);
//退出程序 和job结果进行绑定, 0是正常退出,1是异常退出
System.exit(resultFlag ? 0: 1);
}
}
(四)CovidCountBean2
package beans;
import org.apache.hadoop.io.WritableComparable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* 自定义对象作为数据类型在MR中传递
* 一定要实现Hadoop的序列化机制:接口Writable, ctrl+i 实现两个方法
*/
public class CovidCountBean2 implements WritableComparable<CovidCountBean2> {
//1、封装私有的属性
private long cases; //确诊病例数
private long deaths; //死亡病例数
//2、有参无参构造
public CovidCountBean2() {
}
public CovidCountBean2(long cases, long deaths) {
this.cases = cases;
this.deaths = deaths;
}
/**
*对有参构造进行修改,提供一个set方法
* 自己封装对象的set方法,用于对象属性赋值
*/
public void set(long cases, long deaths) {
this.cases = cases;
this.deaths = deaths;
}
//3、set和get方法
public long getCases() {
return cases;
}
public void setCases(long cases) {
this.cases = cases;
}
public long getDeaths() {
return deaths;
}
public void setDeaths(long deaths) {
this.deaths = deaths;
}
//4、实现对象的方法
// @Override
// public String toString() {
// return "CovidCountBean{" +
// "cases=" + cases +
// ", deaths=" + deaths +
// '}';
// }
//修改一下,返回的都是数据
@Override
public String toString() {
return cases + "\t" + deaths;
}
/**
* 序列化方法,可以控制把哪写字段序列化出去
*/
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeLong(cases);
dataOutput.writeLong(deaths);
}
/**
* 反序列化方法
* todo 注意反序列化的顺序和序列化顺序一致
*/
@Override
public void readFields(DataInput dataInput) throws IOException {
this.cases = dataInput.readLong();
this.deaths = dataInput.readLong();
}
/**
*自定义对象的排序方法
* 返回结果: 0 相等, 负数 小于, 正数 大于
* 倒序精髓:如果大于,强制返回负数; 如果小于,强制返回正数
*/
@Override
public int compareTo(CovidCountBean2 o) {
return this.cases - o.getCases() > 0 ? -1 : (this.cases - o.getCases() < 0 ? 1 : 0) ;
}
}
本文详细展示了如何使用Hadoop MapReduce框架,通过自定义CovidCountBean2对象和重写Comparator,对美国各州的COVID-19确诊病例数进行倒序排序。通过CovidSortSumMapper和Reducer实现数据处理,最后输出按确诊数递减的州列表。
MapReduce自定义排序案例&spm=1001.2101.3001.5002&articleId=125779608&d=1&t=3&u=774ab4ed879b42a5b5415752125aac81)
8190

被折叠的 条评论
为什么被折叠?



