MapReduce入门详解(以WordCount为例)

大致介绍MapReduce

Hadoop MapReduce是一个软件框架,可以轻松地编写应用程序,在大型集群(数千个节点)上以可靠、容错的方式并行处理大量数据(tb数据集)。
MapReduce作业通常将输入数据集分割成独立的块,由map任务以完全并行的方式处理这些块。框架对映射的输出进行排序,然后将其输入到reduce任务中。作业的输入和输出通常都存储在文件系统中。框架负责调度。

MapReduce的优缺点

一、优点
、1)MapReduce易于编程
它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。
2)良好的扩展性
当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
3)高容错性
MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。
4)适合PB级以上海量数据的离线处理
可以实现上千台服务器集群并发工作,提供数据处理能力。
二、缺点
1)不擅长实时计算
MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果。
2)不擅长流式计算
**流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。**这是因为MapReduce自身的设计特点决定了数据源必须是静态的。
3)不擅长DAG(有向无环图)计算
**即不擅长多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。**在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

以WordCount为例介绍MapReduce的核心思想(重点)

大致流程图

在这里插入图片描述

1)Input split阶段

在进行Map之前,Hadoop会根据输入文件的大小进行一次分割。分割后,会形成一个Key-Value键值对,这个键值对会被当作Map的输入键值对。一般而言,该键值对是(输入分割好文件的位置-分割的数据)。注意:一般而言,切割的成碎片的大小和HDFS的块大小相近。如果我们的HDFS的Block块大小为128MB,然后,有三个输入文件,大小分别为10MB,256MB,127MB。
那么就会形成5个MapTask。每一个MapTask回去执行各自里面的数据。
以WordCount为例:

假设我们现在有三个文件大小分别为10MB,256MB,127MB。那么它会在Input split阶段被分割成5个MapTask、分别为10MB,两个128MB,一个128MB。里面保存的就是数据。

2)Map阶段

前面我们已经进行了Input Split。形成了5个MapTask。那么在每个MapTask中还是会进行切割,此时的切割是根据数据进行的切割。切割的结果仍然是Key-Value键值对。该切割的键值对是Map的输入键值对。这些键值对进行输入后,会在经过程序员自己重写的map函数进行处理。
以WordCount为例:

切割好的键值对为:(位置偏移量-文件内容) 如
0-Hadoop Java
13-Hadoop Java
27-Zookeeper

以上键值对会作为map函数的输入键值对。然后进入map类进行处理

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

    private Text outKey = new Text();
    private IntWritable outValue = new IntWritable(1);

    @Override
    //注意:LongWritable key, Text value, 即使上面的键值对
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        String line = value.toString();
        String words[] = line.split(" ");
        for (String word : words) {
            outKey.set(word);
            context.write(outKey, outValue);
        }

    }
}

在上面的map函数进行处理到 context.write(outKey, outValue);这一步时,就相当于Map完成。例如 生成了 Hadoop 1。这个键值对会保存在Context中。(Context主要用于完成Map和Reduce的交互对接,这是笔者的理解,有什么不对的地方,欢迎大家在评论区留言)。
当所有的MapTask都进行完之后,相当于Map阶段已经完成。而每个MapTask将所有的输出键值对保存再了Context中。

Map Task流程图

MapTask于Context的交互过程如下图所示:
在这里插入图片描述

3)Shuffting阶段

该阶段过于复杂,暂时不讲,之后会在开一个博客细讲。大家在这里就先了解,在Map阶段结束后,所有的输出键值对会进行sort(排序)和整合(即相同的会组合到一起生成一个新的键值对,该键值对即使Reduce的输入键值对
以上述WordCount为例子:
Map的输出键值对会被整理成
<Hadoop ,(1,1)>
<Java (1,1)>
<Zookeeper(1,0)>
<Hive,(1.0)>
<C++,(1,0)>
<BigData,(1,0)>
以上键值对会成为Reduce的输入键值对

4)Reduce阶段

Reduce的模式基本和Map的模式差不多。不同的是,Reduce所需要的输入键值对是经过Map,Shuffit之后形成的键值对。它会根据前面的生成的Map Task的个数和最后Map输出键值对的大小来生成对应的Reduce Task。
Reduce Task对生成最终结果。所有Reduce Task的结果整合就是最终的结果。
以上述WordCount为例,解释Reduce

package com.mapreducer.WordCount;

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

import java.io.IOException;

/**
 * @author 杨铭
 * 2022/4/15,22:04
 */
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
   private IntWritable outValue= new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        int sum=0;
        //key :hadoop value:(1,1);
        //累加计数
        for (IntWritable value : values) {
            sum+=value.get();
        }
        outValue.set(sum);
        context.write(key,outValue);
    }
}

Reduce Task的流程图

在这里插入图片描述

提交Job

提交Job中的原理属于Yarn的内容,后续,博主在编写Yarn相关博客时,会在细讲。
作业提交的代码是一个固定的步骤,以WordCount为例,如下:

package com.mapreducer.WordCount;

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

import java.io.IOException;

/**
 * @author 杨铭
 * 2022/4/15,22:11
 */
public class WordCountDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //1、获取Job
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        //设置jar包路径
        job.setJarByClass(WordCountDriver.class);
        //3、关联map和reducer
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        //4、设置map的输出kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //5、设置最终输出的kv类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //6、设置输入输出路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        //7、提交job
        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);

    }
}

附件(MapReduce中的变量和Java中变量的对应关系)

Java类型Hadoop Writable类型
BooleanBooleanWritable
ByteByteWritable
IntIntWritable
FloatFloatWritable
LongLongWritable
DoubleDoubleWritable
StringText
MapMapWritable
ArrayArrayWritable
NullNullWritable

博主写博客不易,希望大家可以点赞,关注!谢谢!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值