原始的数据如图所示:
我要按照第六个字段的大小进行分区,大于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服务器
然后运行得到的结果如下:
因为设置了两个reduceTask,最后生成了两个结果输出文件
打开如图所示:
这个都是小于15的数据区
大于15的数据区: