大数据学习之hadoop——11MapReduce组成结构_WordCount案例

标准的MapReduce程序的基础由Mapper-Reducer-Driver三部分组成

一. Mapper类

1、继承org.apache.hadoop.mapreduce.Mapper类,设置四个泛型< KeyIn ValueIn KeyOut ValueOut>
KeyIn ValueIn一般都是LongWritable和Text不变(MapReduce默认读取文件的类型为.txt),后两个泛型是向context传递的KeyOut ValueOut类型。当输入Mapper的文件类型为序列化文件时, KeyIn ValueIn可以更改为序列化文件key-value对应的序列化类型
2、hadoop提供的序列化类型特点:实现WritableComparable接口,重写readFields()、write()、compareTo()方法。部分常用的序列化类型
IntWritable、LongWritable,FloatWritable、DoubleWritable、NullWritable

2、 继承Mapper类之后要重写map方法,默认情况下map方法的三个参数分别为:LongWritable(KeyIn),value(默认为一行数据),context(上下文变量)。
默认情况下Map Reduce程序将每一个文件切片后按照行读取。将一行的数据存储至value中传递给map方法,在map方法中对于每行数据根据自定义的正则表达式进行分割,分割成最小数据单元后将其按照一定的对应规则赋值给Key,Value,传递到Context对象中,以便于reduce程序进行下一步处理。值得注意的是,对于context对象来说只能接受hadoop提供的序列化类型的参数传递
3、继承mapper类之后还可以重写setUp(),cleanUp()两个方法。setUp方法可以理解为执行maptask任务之前程序进行的初始化操作。cleanUp方法可以理解为执行完所有maptask任务之后进行的收尾工作。我们可以根据其方法特性以及业务逻辑重写这两个方法。

二、Reducer类

1、一个标准的Reducer类需要继承org.apache.hadoop.mapreduce.Reducer类,设置四个泛型(KeyIn ValueIn KeyOut ValueOut):Reducer端的keyin-valuein数据类型与Mapper端的keyout-valueout数据类型相同。Reducerr端的keyout-valueout,则是代表了Reducer向context写入的数据类型。
2、继承Reducer类之后要重写reduce方法,reduce方法的三个参数与mapper端的keyout-valueout相关:第一个参数的数据类型为mapper端的keyout数据类型,第二个参数的数据类型为Iterable迭代器,第三个类型为context(上下文变量)。reducer将Context对象中的数据拉取过来,key相同的value值归为一组数据,存储至Iterable迭代器中,执行reduce函数时我们可以遍历该迭代器对key相同的一组value数据进行操作。
3、只有所有maptask任务执行结束之后才会开始执行reducetask任务,并且默认情况下reducetask只有一个,且在同一个reducetask任务中会根据key的个数执行多次reduce方法。
4、在所有reducetask任务执行结束之后,按Driver类中的设置,context内的数据会写到文件中。输出方式我们可以选择普通的txt文本方式,或者seq序列化文件方式,后文中会到。

三、Driver程序

1、在Driver程序中,我们需要实现的基础是创建Job实例以及“四三二一”

  • 创建Job实例
Job job = Job.getInstance();
  • 四:向Job对象中设置Mapper端的KeyOutValueOut泛型,Reducer端的keyOut-ValueOut
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
  • 三:向Job对象设置Mapper、Reducer、Driver类
job.setJarByClass(xxxDriver.class);
job.setMapperClass(xxxMapper.class);
job.setReducerClass(xxxReducer.class);
  • 二:设置MapReduce涉及文件的输入输出路径
Path inputPath = new Path("文件输入路径");
Path outputPath = new Path("文件输出路径");
  • 一:提交Job任务
System.out.println(job.waitForCompletion(true));

2、在Driver类中,我们可以通过job.setxxx()的方式设置其他的任务属性,例如Sort、Grouping等等
在这里插入图片描述

四、小结

1、Mapper、Reducer、Driver可以以内部类的方式写在同一个类中。
2、根据文件数据量的大小,会生成多个maptask任务,当所有maptask任务执行结束之后,开会开始执行reducetask任务.默认情况下reducetask数量为1,但是可以通过job.setNumReduceTasks()设置。
3、在输入输出路径位置,最好先判断输出路径是否存在,如不存在就创建,存在就删除,因为在mapreduce中会按照输出目录自动创建文件夹和输出文件。

五、基础案例:wordCount

案例目的:统计数据格式为xxx xxx的文件中所有单词的数量,wordCount在mapReduce程序中的地位相当于helloword在java程序的地位

  • Mapper
package MapReduce.WordCount;

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

import java.io.IOException;

/**
 * Mapper里有四种泛型
 *  keyin valuein keyout valueout
 *  注意:所有的泛型一定是可以序列化的(与java中的序列化原理一样,表现形式不同)
 *  文件作为mapper的输入,最小的数据单元以键值对的形式作为输出
 *  LongWritable:文件的偏移量
 *      偏移量:能控制文件中每行数据开头的数字
 *  Text:文件每行的实际内容
 *  Text:输出时候的那个单词
 *  IntWritable:每个单词对应的数字1
 *
 *  setUp:任务开始时,最先开始执行的程序,仅执行一次,相当于初始化一些内容。一般不重写
 *  map:每来一个键值对,都要执行一次map方法,划分最小数据单元的操作就在这里执行。一般需要重写
 *  cleanUp:任务结束时,最后执行的程序,仅执行一次,相当于做一些收尾工作。一般不重写
 *  run:涉及一些核心的内容,没有极特殊情况不重写
 */
public class WordCountMapper extends Mapper<LongWritable,Text,Text,IntWritable> {
    
    
    Text outkey = new Text();
    IntWritable outvalue = new IntWritable();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    
    
        //把从文件读出的每行的内容变成我们熟悉的String类型
        String line = value.toString();
        //把每行内容划分成每个独立的单词
        //split参数为正则表达式
        //String[] words = line.split(" ");
        String[] words = line.split("\t");
        //循环遍历数组,把数组中的每个单词以(key,1)输出到reduce
        for(String word:words){
    
    
            //输出的一种简便写法
//            context.write(new Text(word),new IntWritable(1));
            //标准写法 分别设置key和value
            outkey.set(word);
            outvalue.set(1);
            //把设置好的key和value发送到reduce
            context.write(outkey,outvalue);
        }

    }
}

  • Reducer
package MapReduce.WordCount;

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

import java.io.IOException;

public class WordCountReducer extends Reducer<Text,IntWritable,Text,IntWritable> {
    
    
    IntWritable outvalue = new IntWritable();
    static int i =0;
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
    
    
        //求和的初始值
        System.out.println(i++);
        int sum = 0;
        //每一个单词 把带来的序列化数字进行相加求和
        for (IntWritable value:values){
    
    
            sum += value.get();
        }
        //设置当前单词的总和作为value
        outvalue.set(sum);
        //把最终结果(key,sum)写入文件
        context.write(key,outvalue);
    }
}


  • Driver
package MapReduce.WordCount;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.net.URI;

public class WordCountDriver {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //创建一个job的实例
        Job job = Job.getInstance();

        //4 设置4个输出泛型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //3 设置三个类(Mapper,Reducer,Driver)
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        //2 设置两个路径(输入和输出)
        Path inputPath = new Path("file:///E:/idea-workSpace/HaoopText/WordCount/input");
        Path outputPath = new Path("file:///E:/idea-workSpace/HaoopText/WordCount/output");
        //通过输出路径创建文件系统的流
        FileSystem fs = FileSystem.get(new URI(outputPath.toString()),new Configuration());
        //判断输出目录是否存在,存在就删除,不然下面会报错(输出路径已存在)
        if (fs.exists(outputPath)){
    
    
            fs.delete(outputPath, true);
        }
        FileInputFormat.setInputPaths(job,inputPath);
        //输出文件将自动创建文件夹,所以不存在于文件系统中
        FileOutputFormat.setOutputPath(job,outputPath);

        //1 提交job任务
        System.out.println(job.waitForCompletion(true));
    }
}

猜你喜欢

转载自blog.csdn.net/nothair/article/details/105235573
今日推荐