【MapReduce API编程】体验shuffle排序、分区、自定义排序

本文介绍了如何在ApacheHadoopMapReduce框架中,通过自定义Mapper、Partitioner和Reducer对文本中的数字进行排序处理,包括使用shuffle机制和自定义分区规则。
摘要由CSDN通过智能技术生成

问题:对文本中的数字进行排序处理

        对数字进行排序体验shuffle排序、自定义分区规则和自定义排序。

首先创建一个TXT文本,文本内容如下。

shuffle是存在于map和reduce之间的一个过程,该过程会根据定义的key值进行默认升序排序。如何设置key值在下面Mapper类中有注释解释。(设置key值要注意修改mapper的输出类型和主类中设置的map输出类不一致会出错。)

程序入口类:

package shuffle;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class NumNDemo {

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();

		Job job = Job.getInstance(conf);
        //配置主类
		job.setJarByClass(NumNDemo.class);
		//配置mapper类
		job.setMapperClass(NumMapper.class);
		//配置reduce类
		job.setReducerClass(NumReducer.class);

		//指定分区规则
		job.setPartitionerClass(NumPartitioner.class);
		//设置reduce数量
		job.setNumReduceTasks(3);

		job.setMapOutputKeyClass(NullWritable.class);// map阶段的输出的key
		job.setMapOutputValueClass(IntWritable.class);// map阶段的输出的value

		job.setOutputKeyClass(NullWritable.class);// reduce阶段的输出的key
		job.setOutputValueClass(IntWritable.class);// reduce阶段的输出的value
        //文件存在的地址
		FileInputFormat.setInputPaths(job, new Path("./src/main/java/shuffle/num.txt"));
        //运行结果的输出地址
		FileOutputFormat.setOutputPath(job, new Path("./src/main/java/shuffle/output"));

		boolean res = job.waitForCompletion(true);
		System.exit(res ? 0 : 1);
	}

}

Mapper类:

package shuffle;

import org.apache.hadoop.io.IntWritable;
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.util.TreeMap;

public class NumMapper extends Mapper<LongWritable, Text, NullWritable, IntWritable> {
    //在map段进行数据排序处理
    
    //使用TreeMap进行排序
	private TreeMap<Integer, String> repToRecordMap = new TreeMap<Integer, String>();

	//10 3 8 7 6 5 1 2 9 4
	//11 12 17 14 15 20
	//19 18 13 16
	
	@Override
	public void map(LongWritable key, Text value, Context context) {
		String line = value.toString();
		String[] nums = line.split(" ");
		System.out.print("<");
		for (String num : nums) {
			int a=Integer.parseInt(num);
			System.out.print(a+";");
			//自定义排序
			repToRecordMap.put(a, " ");
			//只保留前5个
//			if (repToRecordMap.size() > 5) {
//				repToRecordMap.remove(repToRecordMap.firstKey());
//			}
		}System.out.println(">");
	}
	@Override
	protected void cleanup(Context context) {
	    //对自定义排序的内容进行类型处理,然后交给reduce处理
		for (Integer i : repToRecordMap.keySet()) {
//            System.out.println("keySet:" + i);
			try {
                //此处可以设置key值,从而在shuffle中根据该key值进行升序排序
                //此处key设置为NullWritable.get(),没有利用shuffle的排序。
				context.write(NullWritable.get(), new IntWritable(i));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

Reduce类:在这里使用TreeMap可以进行自定义排序规则,同时也可以在这里设置分区后 一个分区内的数据排序情况。(TreeMap怎么使用这里不再赘述)

package shuffle;

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

import java.io.IOException;
import java.util.Comparator;
import java.util.TreeMap;

class Compareclass implements Comparator<Integer> {
    //返回一个基本类型的整型,谁大谁排后面(升序).
    //返回负数表示:o1 小于o2
    //返回0表示:表示:o1和o2相等
    //返回正数表示:o1大于o2。
    //默认用o1-o2,创建TreeMap对象时可以不用这个继承类,但是要降序,必须修改compare里面的逻辑o2-o1
    //谁大谁排在前面(降序)用o2-o1
    @Override
    //在reduce端进行排序处理
    //修改排列顺序
    public int compare(Integer o1, Integer o2) {
        // TODO Auto-generated method stub
        return o1 - o2;
    }
}

public class NumReducer extends Reducer<NullWritable, IntWritable, NullWritable, IntWritable> {
    Comparator comparetor = new Compareclass();//TreeMap对象可以使用降序的比较器
    private TreeMap<Integer, String> repToRecordMap =
            new TreeMap<Integer, String>(comparetor); //如果参数为空是默认升序比较器

    public void reduce(NullWritable key, Iterable<IntWritable> values, Context context)
            throws IOException, InterruptedException {
        System.out.println("Reduce输入:");
        for (IntWritable value : values) {
            int a = value.get();
            System.out.print(a + ";");
            repToRecordMap.put(a, " ");
            //只保留前5个数据
//            if (repToRecordMap.size() > 5) {
//                repToRecordMap.remove(repToRecordMap.firstKey());
//            }
        }

        System.out.println();

        System.out.println("Reducer计算结果:");
        System.out.print("<");
        for (Integer i : repToRecordMap.keySet()) {
            System.out.print(i + ";");
            context.write(NullWritable.get(), new IntWritable(i));
        }
        System.out.println(">");

    }
}

建立分区规则:在这里设置分区的规则,我在这里设置小于10的放在第一个分区,小于20大于10的放在第二个分区,其他的放在第三个分区。注意:分区是从0开始的要注意getPartition()方法的返回值,否则会出错。

package shuffle;

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

/**
 * @auther start
 * @create 2023-11-12 20:18
 */
public class NumPartitioner extends Partitioner<NullWritable, IntWritable> {
    @Override
    //自定义分区规则,数据在v2中
    public int getPartition(NullWritable k2, IntWritable v2, int numPartitions) {
        System.out.println("----------Partition--------------");
        int i = v2.get();
        if (i < 10) {
            return 0;
        } else if (i < 20) {
            return 1;
        } else
            return 2;
    }
}

结果:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值