原始的数据如图所示:

mapreduce 分区和reduce任务是怎么关联的_hadoop


我要按照第六个字段的大小进行分区,大于15的分成一区,小于15的分成一区。

实现的流程如下:

首先,需要四个类,自定义的partition类,Mapper类,Reduce类和负责任务整体调度的partitionMain类。

各个类的代码如下:

自定义partitioner类

里面设置了我们的分区的逻辑,即以15为分割线将数据进行分区。

package com.legendlee.partition;

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

public class partitionOwn extends Partitioner<Text,NullWritable> {
    /**
     * 这个方法就是我们自己来定义如何分区
     * @param text 行文本内容
     * @param nullWritable v2
     * @param numPartitions reduceTask的数量
     * @return
     */
    @Override
    public int getPartition(Text text, NullWritable nullWritable, int numPartitions) {
        //将文本的内容进行切割,返回的是字符串的数组
        String[] split = text.toString().split("\t");
        //取第六行的数据然后进行分区
        String result = split[5];
        if(null!= result&&result!=""){
            if(Integer.parseInt(result)>15){
                return 0;
            }else {
                return 1;
            }
        }
         return 0;
    }
}

Mapper类

package com.legendlee.partition;

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

import java.io.IOException;

/**
 * mapper<k1,v1,k2,v2>
 *     k1:行偏移量
 *     v1:行文本的内容
 *     k2:行文本的内容
 *     v2:NullWritable
 */
public class partitionMapper extends Mapper<LongWritable,Text,Text,NullWritable>{

    //直接把k2的内容写出去即可
    /**
     *mapper的作用就是将文本的内容写出去
     * @param key 行偏移量
     * @param value 行文本的内容
     * @param context 上下文对象
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        context.write(value,NullWritable.get());
    }
}

首先需要思考两个问题,mapper接收和输出的都是什么数据?mapper要实现的功能逻辑是什么?
接收的数据:
k1:行偏移量
v1:行文本的内容
输出的数据:
k2:行文本的内容
v2:可以直接省略NullWritable
实现的功能逻辑:
因为我们在自定义partitioner中实现了分区的逻辑,所以在mapper阶段,只需将数据输出给reduce即可。
Reduce类

package com.legendlee.partition;

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

import java.io.IOException;

public class partitionReducer extends Reducer<Text,NullWritable,Text,NullWritable> {
    /**
     * reduce阶段不做任何处理  直接把行文本输出即可
     * @param key
     * @param values
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
//    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        context.write(key,NullWritable.get());
    }
}

同理分析
partionMain类

package com.legendlee.partition;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.lib.HashPartitioner;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

//固定写法
public class partionMain extends Configured implements Tool {
    /**
     * run方法实现整个任务的调度
     * @param args
     * @return
     * @throws Exception
     */
    @Override
    public int run(String[] args) throws Exception {
        //创建一个job对象
        Job job = Job.getInstance(new Configuration(), "legendlee");
        //设置打包类型
        job.setJarByClass(partionMain.class);
        //第一步:读取文件,解析成key,value对
        job.setInputFormatClass(TextInputFormat.class);
        //添加要读取的文件的路径,path的路径作为参数进行动态的传递
        TextInputFormat.addInputPath(job,new Path(args[0]));
        //第二步:自定义map的逻辑
        job.setMapperClass(partitionMapper.class);
        //设置map输出的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(NullWritable.class);
        //第三步:设置分区类
        job.setPartitionerClass(partitionOwn.class);
        //第四步到第六步省略
        //第七步:自定义reduce逻辑
        job.setReducerClass(partitionReducer.class);
        //设置reduce的输出的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        //设置reduce的个数
        job.setNumReduceTasks(2);
        //第八步:设置输出类
        job.setOutputFormatClass(TextOutputFormat.class);
        //输出路径不写死   通过参数传递
        TextOutputFormat.setOutputPath(job,new Path(args[1]));
        boolean b = job.waitForCompletion(true);
        return b?0:1;
    }

    public static void main(String[] args) throws Exception {
        //main方法主要通过ToolRunne.run将程序跑起来
        int run = ToolRunner.run(new Configuration(), new partionMain(), args);
        System.exit(run);

    }
}

然后将工程打成jar包

将jar包放在Linux服务器

然后运行得到的结果如下:

mapreduce 分区和reduce任务是怎么关联的_hadoop_02


因为设置了两个reduceTask,最后生成了两个结果输出文件

mapreduce 分区和reduce任务是怎么关联的_Text_03


打开如图所示:

这个都是小于15的数据区

mapreduce 分区和reduce任务是怎么关联的_Text_04


大于15的数据区:

mapreduce 分区和reduce任务是怎么关联的_apache_05