hadoop:二次排序

一、 实验目的 1. 进一步立即 MapReduce 思想 2. 编写 SecondarySort 程序。
二、 实验要求 1. 要能理解 MapReduce 编程思想 2. 会编写 MapReduce 版本二次排序程序 3. 其执行并分析执行过程。
三、 实验原理 MR 默认会对键进行排序,然而有的时候我们也有对值进行排序的需求。满足这种 需求一是可以在 reduce 阶段排序收集过来的 values,但是,如果有数量巨大的 values 可 能就会导致内存溢出等问题,这就是二次排序应用的场景——将对值的排序也安排到 MR 计算过程之中,而不是单独来做。 二次排序就是首先按照第一字段排序,然后再对第一字段相同的行按照第二字段排 序,注意不能破坏第一次排序的结果。
四、 实验步骤

新建一个IntPair类

package com.buaa;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.WritableComparable;

public class IntPair implements WritableComparable{
    private int first;
    private int second;

    public IntPair(){
    }

    public IntPair(int left, int right){
        set(left, right);
    }

    public void set(int left, int right){
        first = left;
        second = right;
    }

    @Override
    public void readFields(DataInput in) throws IOException{
        first = in.readInt();
        second = in.readInt();
    }

    @Override
    public void write(DataOutput out) throws IOException{
        out.writeInt(first);
        out.writeInt(second);
    }

    @Override
    public int compareTo(IntPair o)
    {
        if (first != o.first){
            return first < o.first ? -1 : 1;
        }else if (second != o.second){
            return second < o.second ? -1 : 1;
        }else{
            return 0;
        }
    }

    @Override
    public int hashCode(){
        return first * 157 + second;
    }

    @Override
    public boolean equals(Object right){
        if (right == null)
            return false;
        if (this == right)
            return true;
        if (right instanceof IntPair){
            IntPair r = (IntPair) right;
            return r.first == first && r.second == second;
        }else{
            return false;
        }
    }

    public int getFirst(){
        return first;
    }

    public int getSecond(){
        return second;
    }
}

新建一个SecondarySort类

package com.buaa;

import java.io.IOException;
import java.util.StringTokenizer;

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.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;


@SuppressWarnings("deprecation")
public class SecondarySort {
    public static class Map extends Mapper {

        public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            StringTokenizer tokenizer = new StringTokenizer(line);
            int left = 0;
            int right = 0;
            if (tokenizer.hasMoreTokens()) {
                left = Integer.parseInt(tokenizer.nextToken());
                if (tokenizer.hasMoreTokens())
                    right = Integer.parseInt(tokenizer.nextToken());
                context.write(new IntPair(left, right), new IntWritable(right));
            }
        }
    }

    /*
     * 自定义分区函数类FirstPartitioner,根据 IntPair中的first实现分区
     */
    public static class FirstPartitioner extends Partitioner{
        @Override
        public int getPartition(IntPair key, IntWritable value,int numPartitions){
            return Math.abs(key.getFirst() * 127) % numPartitions;
        }
    }

    /*
     * 自定义GroupingComparator类,实现分区内的数据分组
     */
    @SuppressWarnings("rawtypes")
    public static class GroupingComparator extends WritableComparator{
        protected GroupingComparator(){
            super(IntPair.class, true);
        }

        @Override
        public int compare(WritableComparable w1, WritableComparable w2){
            IntPair ip1 = (IntPair) w1;
            IntPair ip2 = (IntPair) w2;
            int l = ip1.getFirst();
            int r = ip2.getFirst();
            return l == r ? 0 : (l < r ? -1 : 1);
        }
    }

    public static class Reduce extends Reducer {

        public void reduce(IntPair key, Iterable values, Context context) throws IOException, InterruptedException {
            for (IntWritable val : values) {
                context.write(new Text(Integer.toString(key.getFirst())), val);
            }
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        // 读取配置文件
        Configuration conf = new Configuration();

        // 判断路径是否存在,如果存在,则删除
        Path mypath = new Path(args[1]);
        FileSystem hdfs = mypath.getFileSystem(conf);
        if (hdfs.isDirectory(mypath)) {
            hdfs.delete(mypath, true);
        }

        Job job = new Job(conf, "secondarysort");
        // 设置主类
        job.setJarByClass(SecondarySort.class);

        // 输入路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        // 输出路径
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        // Mapper
        job.setMapperClass(Map.class);
        // Reducer
        job.setReducerClass(Reduce.class);

        // 分区函数
        job.setPartitionerClass(FirstPartitioner.class);

        // 本示例并没有自定义SortComparator,而是使用IntPair中compareTo方法进行排序 job.setSortComparatorClass();

        // 分组函数
        job.setGroupingComparatorClass(GroupingComparator.class);

        // map输出key类型
        job.setMapOutputKeyClass(IntPair.class);
        // map输出value类型
        job.setMapOutputValueClass(IntWritable.class);

        // reduce输出key类型
        job.setOutputKeyClass(Text.class);
        // reduce输出value类型
        job.setOutputValueClass(IntWritable.class);

        // 输入格式
        job.setInputFormatClass(TextInputFormat.class);
        // 输出格式
        job.setOutputFormatClass(TextOutputFormat.class);

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

导入lib包
步骤如下:
#导入hadoop文件夹路径下的lib包。
1.点击file>Project Structure>Modules>+号>Library下的java找到你自己的lib文件然后ok。完成后打jar包。
jar包操作如下:
hadoop:二次排序_第1张图片
hadoop:二次排序_第2张图片
勾选Include in project build 点击ok就完成了jar的打包
然后点击Buildhadoop:二次排序_第3张图片
完成后就会出现一下jar包
hadoop:二次排序_第4张图片
然后将这个包用ftp上传到hadoop中
然后用

用start-all.sh启动hadoop
创建输入和输出的文件夹;
2.创建hadoop fs -mkdir -p /datas/in , hadoop fs -mkdir -p /datas/out
3创建secsortdata.txt文档
在这里插入图片描述
hadoop:二次排序_第5张图片
用ftp传到hadoop中。
5把上传到hadoop中的txt文档用hadoop fs -put secsortdata.txt /datas/in上传到hdfs中
6.在你java的jar包路径下执行
hadoop jar wordcount.jar /datas/in/secsortdata.txt /datas/out
hadoop:二次排序_第6张图片
然后用hadoop fs -cat /datas/out/part-r-00000
查看
在这里插入图片描述
这样就成功了。

你可能感兴趣的:(hadoop:二次排序)