大数据学习(三)--利用MapReduce对多文件数据进行排序

先来一个小插曲

MapReduce Job中的全局数据

在MapReduce中如何保存全局数据呢?可以考虑以下几种方式

  1. 读写HDFS文件,即将变量存在一个地方
  2. 配置Job属性,即将变量写道配置(Configuration)中
  3. 使用DistributedCache,但是DistributedCache是只读的

排序

首先联想MapReduce过程,先Map,给输入,并给输出。Reduce则是将结果处理进行计算。
在MapReduce过程中本身就有排序,MapReduce的默认排序是按照key值进行排序,如果key为int的IntWritable,则按照大小排序,如果key为String,则按照ascii 码进行排序。
但是有个问题,Reducer自动排序的数据仅仅是发送到自己节点数据,使用默认的排序并不能保证全局的顺序,因为在排序前还有个partition的过程,即能保证内部顺序性,而无法保证节点之间数据顺序性。
那么为了完全实现内部节点之间的顺序性,那么就需要自定义Partition类,保证执行Partition过程之后所有Reduce上的数据在整体上是有序的。
本代码以以下思路进行:

  1. 将读入的数据转化成IntWritable型,然后将值作为key输出(value任意)
  2. 重写partition,保证整体有序,用输入数据的最大值a除以系统partition数量b的商c作为分割数据的边界增量,也就是说分割数据的边界是这个商c的1倍,2倍至partition-1倍。这样就能保证执行partition后的数据是整体有序的。
  3. Reduce获得<key, value-list>后,根据value-list中元素个数,将输入的key作为value的输出次数(即有相同的就输出多个),输出的key是一个全局变量,用于统计当前key的位次(即在所有数中排第几)。

示例参数

file01:

2
31
212
32
231
12
2
34
12
12

file02

32
2
4
5
6
7
8
9
0
0
1212
12
12

file03

78
56
45
34
23
56
76
67
54
2

示例输出:
在这里插入图片描述

源码

最后给出源码,便于大家理解:

package com.anla.chapter2;

import org.apache.hadoop.conf.Configuration;
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.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

import java.io.IOException;

/**
 * @user anLA7856
 * @time 19-3-22 下午4:38
 * @description
 */
public class Sort {

    public static class Map extends Mapper<Object, Text, IntWritable, IntWritable> {
        private static IntWritable data = new IntWritable();

        @Override
        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();    // 因为一行一个
            data.set(Integer.parseInt(line));
            context.write(data, new IntWritable(1));
        }
    }

    public static class Reduce extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
        private static IntWritable lineNum = new IntWritable(1);

        @Override
        protected void reduce(IntWritable key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            for (IntWritable val : values){
                context.write(lineNum, key);      // key 为1,最终value为key
                lineNum = new IntWritable(lineNum.get()+1);    // 简单自增
            }
        }
    }

    public static class Partition extends Partitioner<IntWritable, IntWritable>{

        public int getPartition(IntWritable key, IntWritable value, int numPartitions) {
            int maxNumber = 65223;
            int bound = maxNumber / numPartitions + 1;
            int keyNumber = key.get();
            for (int i = 0;i < numPartitions; i++) {
                if (keyNumber > bound*numPartitions && keyNumber < bound *(numPartitions + 1)) {
                    return numPartitions;
                }
            }
            return -1;
        }
    }

    public static void main(String[] args) throws Exception{
        Configuration configuration = new Configuration();
        String[] otherArgs = new GenericOptionsParser(configuration, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.out.println("Usage: Sort <in> <out>");
            System.exit(2);
        }
        Job job = Job.getInstance(configuration, "sort");
        job.setJarByClass(Sort.class);
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);
        job.setPartitionerClass(Partition.class);
        job.setOutputKeyClass(IntWritable.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
        System.exit(job.waitForCompletion(true) ? 0: 1);
    }
}

运行方法可参看博主上一篇文章:
跟A君学大数据(二)-手把手运行Hadoop的WordCount程序

参考资料:

  1. Hadoop IN Action
  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值