mapreduce总结

一、mapreduce简介

  1. MapReduce是一种分布式计算模型,是hadoop的核心组件之一,是Google提出的,主要用于搜索领域,解决海量数据的计算问题。
  2. MR有两个阶段组成:Map和Reduce,用户只需实现map()和reduce()两个函数,即可实现分布式计算。

MapReduce执行流程

mapreduce总结_第1张图片

  Client: 用来提交MapReduce作业。

  JobTracker: 用来协调作业的运行。

  TaskTracker: 用来处理作业划分后的任务。

MapReduce原理

MapReduce的执行过程:

1、Map任务处理

  • 第一阶段是把输入文件按照一定的标准分片 (InputSplit),每个输入片的大小是固定的。默认情况下,输入片(InputSplit)的大小与数据块(Block)的大小是相同的。如果数据块(Block)的大小是默认值64MB,输入文件有两个,一个是32MB,一个是72MB。那么小的文件是一个输入片,大文件会分为两个数据块,那么是两个输入片,一共产生三个输入片。每一个输入片由一个Mapper进程处理,这里的三个输入片,会有三个Mapper进程处理。
  • 第二阶段是对输入片中的记录按照一定的规则解析成键值对,有个默认规则是把每一行文本内容解析成键值对,这里的“键”是每一行的起始位置(单位是字节),“值”是本行的文本内容。
  • 第三阶段是调用Mapper类中的map方法,在第二阶段中解析出来的每一个键值对,调用一次map方法,如果有1000个键值对,就会调用1000次map方法,每一次调用map方法会输出零个或者多个键值对。
  • 第四阶段是按照一定的规则对第三阶段输出的键值对进行分区,分区是基于键进行的,比如我们的键表示省份(如北京、上海、山东等),那么就可以按照不同省份进行分区,同一个省份的键值对划分到一个区中。默认情况下只有一个区,分区的数量就是Reducer任务运行的数量,因此默认只有一个Reducer任务。
  • 第五阶段是对每个分区中的键值对进行排序。首先,按照键进行排序,对于键相同的键值对,按照值进行排序。比如三个键值 对<2,2>、<1,3>、<2,1>,键和值分别是整数。那么排序后的结果 是<1,3>、<2,1>、<2,2>。如果有第六阶段,那么进入第六阶段;如果没有,直接输出到本地的linux 文件中。
  • 第六阶段是对数据进行归约处理,也就是reduce处理,通常情况下的Comber过程,键相等的键值对会调用一次reduce方法,经过这一阶段,数据量会减少,归约后的数据输出到本地的linxu文件中。本阶段默认是没有的,需要用户自己增加这一阶段的代码。

2、Reduce任务处理

  • 第一阶段是Reducer任务会主动从Mapper任务复制其输出的键值对,Mapper任务可能会有很多,因此Reducer会复制多个Mapper的输出。(shuffle过程)
  • 第二阶段是把复制到Reducer本地数据,全部进行合并,即把分散的数据合并成一个大的数据,再对合并后的数据排序。
  • 第三阶段是对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS文件中

二、java代码实现

实现文件中的单词个数统计

package mapreduce;

import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCountApp {
    static final String INPUT_PATH = "hdfs://hadoop01:9000/hello";
    static final String OUT_PATH = "hdfs://hadoop01:9000/out";

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        FileSystem fileSystem = FileSystem.get(new URI(INPUT_PATH), conf);
        Path outPath = new Path(OUT_PATH);
        if (fileSystem.exists(outPath)) {
            fileSystem.delete(outPath, true);
        }

        Job job = new Job(conf, WordCountApp.class.getSimpleName());

        // 1.1指定读取的文件位于哪里
        FileInputFormat.setInputPaths(job, INPUT_PATH);
        // 指定如何对输入的文件进行格式化,把输入文件每一行解析成键值对
        //job.setInputFormatClass(TextInputFormat.class);

        // 1.2指定自定义的map类
        job.setMapperClass(MyMapper.class);
        // map输出的类型。如果的类型与类型一致,则可以省略
        //job.setOutputKeyClass(Text.class);
        //job.setOutputValueClass(LongWritable.class);

        // 1.3分区
        //job.setPartitionerClass(org.apache.hadoop.mapreduce.lib.partition.HashPartitioner.class);
        // 有一个reduce任务运行
        //job.setNumReduceTasks(1);

        // 1.4排序、分组

        // 1.5归约

        // 2.2指定自定义reduce类
        job.setReducerClass(MyReducer.class);
        // 指定reduce的输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        // 2.3指定写出到哪里
        FileOutputFormat.setOutputPath(job, outPath);
        // 指定输出文件的格式化类
        //job.setOutputFormatClass(TextOutputFormat.class);

        // 把job提交给jobtracker运行
        job.waitForCompletion(true);
    }

    /**
     * 
     * KEYIN     即K1     表示行的偏移量 
     * VALUEIN     即V1     表示行文本内容 
     * KEYOUT     即K2     表示行中出现的单词 
     * VALUEOUT 即V2        表示行中出现的单词的次数,固定值1
     * 
     */
    static class MyMapper extends
            Mapper {
        protected void map(LongWritable k1, Text v1, Context context)
                throws java.io.IOException, InterruptedException {
            String[] splited = v1.toString().split(" ");
            for (String word : splited) {
                context.write(new Text(word), new LongWritable(1));
            }
        };
    }

    /**
     * KEYIN     即K2     表示行中出现的单词 
     * VALUEIN     即V2     表示出现的单词的次数 
     * KEYOUT     即K3     表示行中出现的不同单词
     * VALUEOUT 即V3     表示行中出现的不同单词的总次数
     */
    static class MyReducer extends
            Reducer {
        protected void reduce(Text k2, java.lang.Iterable v2,
                Context ctx) throws java.io.IOException,
                InterruptedException {
            long times = 0L;
            for (LongWritable count : v2) {
                times += count.get();
            }
            ctx.write(k2, new LongWritable(times));
        };
    }
}

 

转载于:https://www.cnblogs.com/suolearn/p/10419681.html

你可能感兴趣的:(大数据,java)