Hadoop的mapreduce需求:统计每个州累计确诊病例。

  1. 数据准备
    us-counties.csv
    链接:https://pan.baidu.com/s/1YRUpIeZNmfO8_g504Q8Vnw
    提取码:8fv8
  2. CovidCountBean编程
package com.covid.bean;

import org.apache.hadoop.io.Writable;

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

/**
 * @author:Yan
 * @date: 2022年08月11日 13:58
 * @desc:自定义对象作为数据类型在MR中传递
 */
public class CovidCountBean implements Writable {
    
    

    private long cases;//确诊病例数
    private long deaths;//死亡病例数

    //空的构造器
    public CovidCountBean(){
    
    

    }

    public CovidCountBean(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;
    }


    //修改一下,返回的都是数据
    @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();
    }
}

  1. map编程
package com.covid.sum;


import com.covid.bean.CovidCountBean;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @author:yan
 * @date: 2022年08月11日 14:03
 * @desc:
 *      需求:统计每个州累计确诊病例。
 *      分析:
 *          自定义一个对象CovidCountBean,用于封装每个县的确诊病例数和死亡病例数。注意需要实现hadoop的序列化机制。
 *          以州state作为map阶段输出的key,以CovidCountBean作为value,这样经过MapReduce的默认排序分组规则,属于同一个州的数据就会变成一组进行reduce处理,
 *          进行累加即可得出每个州累计确诊病例。
 *          LongWritable:偏移量  输入key
 *          Text:输入的值
 *          CovidCountBean:
 */
public class CovidSumMapper extends Mapper<LongWritable, Text, Text, CovidCountBean> {
    
    

    /**
     * 3、创建输出对象
     */
    Text outKey = new Text();
    CovidCountBean outValue = new CovidCountBean();

    /**
     * 1、重写map父类方法:map回车
     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    
    
        /**
         * 2、读取一行数据进行切割
         */
        String[] fields = value.toString().split(",");
        /**
         * 4、提取数据 州、确诊数、死亡数
         */
        //获取州的名字
        String state = fields[2];
        //获得确诊数
        long cases =Long.parseLong(fields[3]) ;
        //获得死亡数
        long dealths = Long.parseLong(fields[4]) ;

        //因为疫情数据中,会有部分数据缺少,正着数就会越界,可以采用倒着数
        outKey.set(state);
        outValue.set(cases,dealths);
        /**
         * 5、输出结果
         */

        context.write(outKey,outValue);
    }
}

  1. reduce编程
package com.covid.sum;


import com.covid.bean.CovidCountBean;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @author:Yan
 * @date: 2022年08月11日 14:07
 * @desc:
 */
public class CovidSumReducer extends Reducer<Text, CovidCountBean,Text,CovidCountBean> {
    
    
    CovidCountBean outvalue = new CovidCountBean();

    @Override
    protected void reduce(Text key, Iterable<CovidCountBean> values, Context context) throws IOException, InterruptedException {
    
    
        /**
         * 创建统计变量
         */
        long totalCases = 0;//累计确诊人数
        long totalDeaths = 0;//累计死亡人数

        /**
         * 遍历该州的各个县的数据
         */
        for (CovidCountBean value : values) {
    
    
            totalCases += value.getCases();  //
            totalDeaths += value.getDeaths();
        }

        /**
         * 输出结果赋值
         */
        outvalue.set(totalCases,totalDeaths);
        context.write(key,outvalue);

    }
}

  1. Driver编程
package com.covid.sum;

/**
 * @author:Yan
 * @date: 2022年08月11日 14:08
 * @desc:
 */


import com.covid.bean.CovidCountBean;
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 CovidSumDriver {
    
    

    public static void main(String[] args) throws Exception {
    
    

        //创建驱动类
        Configuration conf = new Configuration();

        //构造job作业的实例,参数(配置对象,job名字)
        Job job = Job.getInstance(conf, CovidSumDriver.class.getSimpleName());

        //设置mr程序运行的主类
        job.setJarByClass(CovidSumDriver.class);

        //设置本次mr程序的mapper类型、reducer类型
        job.setMapperClass(CovidSumMapper.class);
        job.setReducerClass(CovidSumReducer.class);


        //指定mapper阶段输出的key value数据类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(CovidCountBean.class);

        //指定reducer阶段输出的key value数据类型,也是mr程序最终的输出数据类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(CovidCountBean.class);

        //配置本次作业的输入数据路径和输出数据路径
        Path inputPath = new Path("input/covid");
        Path outputPath = new Path("output/covid/sum");

        //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);

    }

}

  1. 运行Driver

猜你喜欢

转载自blog.csdn.net/m0_58353740/article/details/130655658