分布式计算框架MapReduce

一.介绍

产生背景: web2.0时代到来,大量的数据需要处理,单机处理已经不能满足需求,分布式存储与计算进入历史舞台
是什么:是一个面向大数据处理的计算框架
基本特点:提供可靠的分布式计算,封装了细节开发流程简单,跨语言

二.运行流程

在这里插入图片描述在这里插入图片描述

 在这里插入图片描述

 premap阶段

首先根据输入的文件,进行切片,一个block块就是一片
其中的每一片都会分配给一个map任务
一个计算节点可以并行执行多个map任务
分片完成后要按照回车符号进行kv格式化,k是字节偏移量,v是内容

 map阶段

数据处理 Mapper

比如说将分片的数据的每行按照逗号分割
一个分片会产生一个map任务
一个map任务中会调用多次map方法(多少行就调用一次,map方法是按照行来进行处理的)

分区parttion

默认系统分区的代码如下:
![image.png](https://img-blog.csdnimg.cn/img_convert/d42b353afc88d04e54456fdadaa1a87f.png#clientId=u0122ff83-c9ff-4&from=paste&height=154&id=ufad7a530&margin=[object Object]&name=image.png&originHeight=308&originWidth=732&originalType=binary&ratio=1&size=102530&status=done&style=none&taskId=uc310c768-a5d8-4c57-8c6e-8d1ac9019a6&width=366)
map处理后的key的hash值与上int的最大值,然后模上reduce节点的数量
分区的目的:将kv对儿均匀的发送到reduce节点上,使得reduce节点负载均衡
排序 sort
分区完成后进行排序,按照key进行排序
本地合并 combiner(可选,一般计算平均值的时候不进行这部操作)
排序完成后,按照key相同的进行合并,value合并成一个可迭代的集合
一般在计算平均值的时候不进行这步操作,因为combiner实际上也是调用的reduce类的方法,也会进行局部的求平均,最后结果会变成将多个局部平均再求平均,结果就错了
将结果输出到本地

shuffle阶段

将各个节点上相同分区的数据进行合并然后排序

reduce阶段

该阶段会将key相同的进行合并,这个和combiner一样
合并完了执行reduce方法
每个reduce都会在产生对应的结果文件(hdfs文件)

三.案例

1.单词统计

需求分析
在 hdfs 目录/tmp/tianliangedu/input/wordcount 中有一系列文件,内容均为",“号分隔,
求按”,"号分隔的各个元素的出现频率,输出到目录/tmp/tianliangedu/output/个人用户名的 hdfs
目录中。map

package com.fjh.mapper;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;
import java.util.stream.Stream;

/**
 * @author Antg
 * @date 2021/10/7  18:01
 */
public class Mapper01 extends Mapper<Object, Text,Text, IntWritable> {
    //为了节省空间,这里将每个第一次分割开的单词频率记为1
    private final static IntWritable one =new IntWritable(1);
    //暂时存储每个分割开的单词,节省空间
    private Text word  = new Text();

    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        //将单词按照逗号分割开来
        String[] splitResult = value.toString().split(",");
        //循环将每个单词存储进context对象中
        for(String e:splitResult){
            word.set(e);
            context.write(word,one);
        }
    }
}

reduce

package com.fjh.reduce;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @author Antg
 * @date 2021/10/7  18:09
 */
public class Reduce01 extends Reducer<Text, IntWritable,Text, IntWritable> {
    private IntWritable result = new IntWritable();


    //将map传来的结果进行合并
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;
        //统计每个单词出现的频率
        for (IntWritable val : values) {
            //将 key 组中的每个词频数值 sum 到一起
            sum += val.get();
        }
        result.set(sum);
        //结果逐条输出
        context.write(key,result);

    }
}

2.求和

需求分析
在 hdfs 目录/tmp/tianliangedu/input/wordcount 目录中有一系列文件,内容为","号分
号分
隔,分隔后的元素均为数值类型、字母、中文,求所有出现的数值的和。

map

package com.fjh.mapper;

import com.fjh.util.RegexUtil;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @author Antg
 * @date 2021/10/7  18:01
 */
public class Mapper02 extends Mapper<Object, Text, Text, LongWritable> {
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        String[] split = value.toString().split(",");
        for(String e:split){
            if(RegexUtil.matchNum(e)){
            context.write(new Text("求和结果:"),new LongWritable(Long.parseLong(e)));
            }
        }
    }
}

reduce

package com.fjh.reduce;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @author Antg
 * @date 2021/10/7  18:09
 */
public class Reduce02 extends Reducer<Text, LongWritable,Text, IntWritable> {
    private IntWritable result = new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;
        //统计每个单词出现的频率
        for (LongWritable val : values) {
            //将 key 组中的每个词频数值 sum 到一起
            sum += val.get();
        }
        result.set(sum);
        //结果逐条输出
        context.write(key,result);
    }
}

3.driver类

package com.fjh;
import com.fjh.mapper.*;
import com.fjh.reduce.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * 1-8练习题主函数入口
 * @author Antg
 * @date 2021/10/7  17:36
 */
public class Main {
    //获取配置
    public static final Configuration conf = new Configuration();
    /**
     * 参数一:作业的顺序1-8数字
     * */
    public static void main(String[] args) throws Exception {

        //任务名称
        String jobName = "付君华-作业"+args[0];
        //根据同的参数创建不同的任务
        switch (args[0]){
            case "1":
                System.out.println("作业1--------->");
                workDriverSchedule(jobName, Reduce01.class,Mapper01.class,Reduce01.class, Text.class, IntWritable.class,args[1],args[2]);
                break;
            case "2":
                System.out.println("作业2--------->");
                workDriverSchedule(jobName, null, Mapper02.class,Reduce02.class, Text.class, LongWritable.class,args[1],args[2]);
                break;
            case "3":
                System.out.println("作业3--------->");
                workDriverSchedule(jobName, null, Mapper03.class, Reduce03.class, Text.class, LongWritable.class,args[1],args[2]);
                break;
            case "4":
                System.out.println("作业4--------->");
                workDriverSchedule(jobName, Reduce04.class, Mapper04.class, Reduce04.class, Text.class, IntWritable.class,args[1],args[2]);
                break;
            case "5":
                System.out.println("作业5--------->");
                workDriverSchedule(jobName, null, Mapper05.class, Reduce05.class, Text.class, IntWritable.class,args[1],args[2]);
                break;
            case "6":
                System.out.println("作业6--------->");
                workDriverSchedule(jobName, null, Mapper06.class,Reduce06.class, Text.class, IntWritable.class,args[1],args[2]);
                break;
            case "7":
                System.out.println("作业7--------->");
                workDriverSchedule(jobName, null, Mapper06.class,Reduce06.class, Text.class, IntWritable.class,args[1],args[2]);
                break;
            case "8":
                System.out.println("作业8--------->");
                break;
            default:
                System.out.println("第一个参数错误,范围1-8");
                break;
        }
    }

    public static void workDriverSchedule(String jobName,Class combinerClass,Class mapClass,Class reduceClass,Class jobOutputKeyClass,Class jobOutputValueClass,String inputFilePath,String outputFilePath) throws Exception {
        //创建任务
        Job job =Job.getInstance(conf,jobName);
        //指定执行主类
        job.setJarByClass(Main.class);
        //指定map类
        job.setMapperClass(mapClass);
        //如果有combiner类就指定combiner类
        if(combinerClass!=null){
            job.setCombinerClass(combinerClass);
        }
        //指定reduce类
        job.setReducerClass(reduceClass);
        //指定输出结果的key的类型
        job.setOutputKeyClass(jobOutputKeyClass);
        //指定输出结果的value的类型
        job.setOutputValueClass(jobOutputValueClass);
        //指定输入文件路径
        //修改成多输入的(多个输入用逗号分割)
        String[] input = inputFilePath.split(",");
        for(String filePath:input){
            FileInputFormat.addInputPath(job,new Path(filePath));
        }
        //指定输出结果文件路径
        FileOutputFormat.setOutputPath(job,new Path(outputFilePath));
        //指定job执行模式(等待任务执行完成后,提交任务的客户端才会退出!)
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mizui_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值