MapReduce 排序三种实现方式

42 篇文章 2 订阅
13 篇文章 2 订阅

MapReduce 排序两种实现方式

MapReduce 排序两种实现方式 都是借助重写 compareTo 方法 实现
方式一:借助 MapReduce 按照 Key 排序特性,在WritableComparable实现类中 重写 compareTo 方法
方式二:在 Reduce 阶段 cleanUp方法中将最终结果封装到实现JavaBean对象使用集合的排序方法
方式三:在 Reduce 阶段 cleanUp方法中将最终结果封装到实现Comparable的实现类使用集合的排序方法

方式一

该方式需要两次 MapReduce
第一次 MapReduce 做分类统计
第二次 MapReduce 实现排序

第一次 MapReduce 做分类统计

  1. 第一次 MapReduce 做分类统计 Mapper 类

    package cn.lhz.hadoop.mapreduce.wordcount03;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    import java.io.IOException;
    import java.util.StringTokenizer;
    
    /**
     * map 阶段
     * Mapper<LongWritable, Text, Text, IntWritable>
     * 前两个 LongWritable,Text 为 map 输入数据的类型,LongWritable 文本文件偏移量,Text 是读取一行的内容
     * 后两个 Text,IntWritable 为 map 输出数据的类型 ,map输出 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
      // 定义map输出的value
      private final static IntWritable one = new IntWritable(1);
    
      // 定义map输出的key
      private final Text word = new Text();
    
      /**
       * @param key     map输入偏移量
       * @param value   map输入的内容
       * @param context Mapper.Context 可以利用该对象做 map 的输出操作
       * @throws IOException          IOException
       * @throws InterruptedException InterruptedException
       */
      @Override
      protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        // 将输入的内容转为 java 字符串
        String line = value.toString();
        // 默认分隔为 空格 \t \n \r 可以利用构造方法传入自定义分隔符
        StringTokenizer itr = new StringTokenizer(line);
        while (itr.hasMoreTokens()) {
          // 获取每一行中的每一个单词
          String string = itr.nextToken();
          // 封装 map 阶段输出 key
          word.set(string);
          // 将读取内容安需求输(map阶段输出)
          context.write(word, one);
        }
      }
    }
    
    
  2. 第一次 MapReduce 做分类统计 Reducer 类

    package cn.lhz.hadoop.mapreduce.wordcount03;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    
    /**
     * reduce 阶段
     * Reduce<Text, IntWritable,Text,IntWritable> 中四个泛型 两个为一组
     * 前两个 LongWritable,Text 为 map 输出 reduce 输入 数据的类型,map 输出 reduce 输入 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     * 后两个 Text,IntWritable 为 reduce 输出数据的类型 ,reduce 输出 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
      // 定义 reduce 输出 value
      private IntWritable result = new IntWritable();
    
      @Override
      protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        // 单词数量累加的和
        int sum = 0;
        // 遍历迭代器
        for (IntWritable value : values) {
          // 单词标记累加得到单词数量
          sum += value.get();
        }
        // 封装 reduce 输出 value
        result.set(sum);
        // reduce 输出
        context.write(key, result);
      }
    }
    
    
    1. 第一次 MapReduce 做分类统计 Job 类
    package cn.lhz.hadoop.mapreduce.wordcount03;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.hdfs.DistributedFileSystem;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    import java.net.URI;
    
    
    /**
     * 本地提交 mapreduce 任务到 集群
     * 1、打包项目
     * 2、重新编写代码 添加 本地 jar 文件路径 job.setJar(本地jar文件路径)
     * 3、本地提交
     * 服务器提交 mapreduce 任务到 集群
     * 1、打包项目 注意:代码中不允许出现 job.setJar(本地jar文件路径)
     * 2、上传 jar文件到集群
     * 3、提交 hadoop jar hadoop.jar cn.lhz.hadoop.mapreduce.wordcount03.WordCount
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCount {
    
      public static void main(String[] args) throws Exception {
        // 设置环境变量 hadoop 用户名 为 root
        System.setProperty("HADOOP_USER_NAME", "root");
    
        // 参数配置对象
        Configuration conf = new Configuration();
    
        // 跨平台提交
        conf.set("mapreduce.app-submission.cross-platform", "true");
    
        // 本地运行
        // conf.set("mapreduce.framework.name", "local");
    
        // 设置默认文件系统为 本地文件系统
        // conf.set("fs.defaultFS", "file:///");
    
        // 声明Job对象 就是一个应用
        Job job = Job.getInstance(conf, "word count");
    
        // 本地提交启用该行
        // job.setJar("F:\\新疆大学\\code\\bigdata2024\\bigdata\\hadoop\\target\\hadoop.jar");
    
        // 指定当前Job的驱动类
        job.setJarByClass(WordCount.class);
    
        // 指定当前Job的 Mapper
        job.setMapperClass(WordCountMapper.class);
        // 指定当前Job的 Combiner 注意:一定不能影响最终计算结果 否则 不使用
        job.setCombinerClass(WordCountReduce.class);
        // 指定当前Job的 Reducer
        job.setReducerClass(WordCountReduce.class);
    
        // 设置 map 输出 key 的数据类型
        job.setMapOutputValueClass(Text.class);
        // 设置 map 输出 value 的数据类型
        job.setMapOutputValueClass(IntWritable.class);
        // 设置 reduce 输出 key 的数据类型
        job.setOutputKeyClass(Text.class);
        // 设置 reduce 输出 value 的数据类型
        job.setOutputValueClass(IntWritable.class);
        // 定义 map 输入的路径 注意:该路径默认为hdfs路径
        FileInputFormat.addInputPath(job, new Path("/WordCount/input/wcdata.txt"));
        // 定义 reduce 输出数据持久化的路径 注意:该路径默认为hdfs路径
        Path dst = new Path("/WordCount/result");
    
    //    FileSystem fs = FileSystem.get(conf);
    //    if (fs.exists(dst)) {
    //      fs.delete(dst, true);
    //    }
    
        DistributedFileSystem dfs = new DistributedFileSystem();
        String nameService = conf.get("dfs.nameservices");
        String hdfsRPCUrl = "hdfs://" + nameService + ":" + 8020;
        dfs.initialize(URI.create(hdfsRPCUrl), conf);
        if (dfs.exists(dst)) {
          dfs.delete(dst, true);
        }
        FileOutputFormat.setOutputPath(job, dst);
        // 提交 job
        System.exit(job.waitForCompletion(true) ? 0 : 1);
      }
    }
    
    

第二次 MapReduce 实现排序

  1. 编写JavaBean实现 WritableComparable 重写 compareTo 方法

    package cn.lhz.hadoop.mapreduce.wordcount04;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import org.apache.hadoop.io.WritableComparable;
    
    import java.io.DataInput;
    import java.io.DataOutput;
    import java.io.IOException;
    
    
    /**
     * mapreduce 排序
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Word implements WritableComparable<Word> {
      /**
       * 单词
       */
      private String name;
      /**
       * 单词数量
       */
      private int count;
    
      @Override
      public String toString() {
        return this.name + "\t" + this.count;
      }
    
      @Override
      public int compareTo(Word word) {
        // 按照单词数量降序
        int x = word.getCount() - this.count;
        if (x != 0) {
          return x;
        } else {
          // 如果单词数量相同 按照单词 hash 值 升序
          return this.name.compareTo(word.getName());
        }
      }
    
      /**
       * 序列化
       *
       * @param dataOutput 输出的数据
       * @throws IOException IOException
       */
      @Override
      public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeUTF(this.name);
        dataOutput.writeInt(this.count);
      }
    
      /**
       * 反序列化
       * 读取输入属性顺序与输出属性顺序一直
       *
       * @param dataInput 输入的数据
       * @throws IOException IOException
       */
      @Override
      public void readFields(DataInput dataInput) throws IOException {
        this.name = dataInput.readUTF();
        this.count = dataInput.readInt();
      }
    }
    
    
  2. 第二次 MapReduce Mapper 类 将实现 WritableComparable 接口的类对象,作为 map 阶段输出的 key 实现排序

    package cn.lhz.hadoop.mapreduce.wordcount04;
    
    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;
    
    /**
     * 读取 单词计数 结果
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountMapper extends Mapper<LongWritable, Text, Word, NullWritable> {
      private final Word outKey = new Word();
      private final NullWritable outValue = NullWritable.get();
    
      @Override
      protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Word, NullWritable>.Context context) throws IOException, InterruptedException {
        String[] split = value.toString().split("\t");
        outKey.setName(split[0]);
        outKey.setCount(Integer.parseInt(split[1]));
        context.write(outKey, outValue);
      }
    }
    
    
  3. 第二次 MapReduce Reducer 类 接收 map 阶段输出的 key 后,按需求格式输出

    package cn.lhz.hadoop.mapreduce.wordcount04;
    
    import org.apache.hadoop.io.NullWritable;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    
    /**
     * reduce 阶段
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountReduce extends Reducer<Word, NullWritable, Word, NullWritable> {
      private final NullWritable outValue = NullWritable.get();
    
      @Override
      protected void reduce(Word key, Iterable<NullWritable> values, Reducer<Word, NullWritable, Word, NullWritable>.Context context) throws IOException, InterruptedException {
        context.write(key, outValue);
      }
    }
    
    
  4. 第二次 MapReduce job 类

    package cn.lhz.hadoop.mapreduce.wordcount04;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.hdfs.DistributedFileSystem;
    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;
    
    import java.net.URI;
    
    
    /**
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountDriver {
    
      public static void main(String[] args) throws Exception {
        // 设置环境变量 hadoop 用户名 为 root
        System.setProperty("HADOOP_USER_NAME", "root");
    
        // 参数配置对象
        Configuration conf = new Configuration();
    
        // 跨平台提交
        conf.set("mapreduce.app-submission.cross-platform", "true");
    
        // 本地运行
        // conf.set("mapreduce.framework.name", "local");
    
        // 设置默认文件系统为 本地文件系统
        // conf.set("fs.defaultFS", "file:///");
    
        // 声明Job对象 就是一个应用
        Job job = Job.getInstance(conf, "word count");
    
        // 本地提交启用该行
        // job.setJar("F:\\新疆大学\\code\\bigdata2024\\bigdata\\hadoop\\target\\hadoop.jar");
    
        // 指定当前Job的驱动类
        job.setJarByClass(WordCountDriver.class);
    
        // 指定当前Job的 Mapper
        job.setMapperClass(WordCountMapper.class);
        // 指定当前Job的 Combiner 注意:一定不能影响最终计算结果 否则 不使用
        // job.setCombinerClass(WordCountReduce.class);
        // 指定当前Job的 Reducer
        job.setReducerClass(WordCountReduce.class);
    
        // 设置 map 输出 key 的数据类型
        job.setMapOutputValueClass(Word.class);
        // 设置 map 输出 value 的数据类型
        job.setMapOutputValueClass(NullWritable.class);
        // 设置 reduce 输出 key 的数据类型
        job.setOutputKeyClass(Word.class);
        // 设置 reduce 输出 value 的数据类型
        job.setOutputValueClass(NullWritable.class);
        // 定义 map 输入的路径 注意:该路径默认为hdfs路径
        FileInputFormat.addInputPath(job, new Path("/WordCount/result/part-r-00000"));
        // 定义 reduce 输出数据持久化的路径 注意:该路径默认为hdfs路径
        Path dst = new Path("/WordCount/sort");
    
    //    FileSystem fs = FileSystem.get(conf);
    //    if (fs.exists(dst)) {
    //      fs.delete(dst, true);
    //    }
    
        DistributedFileSystem dfs = new DistributedFileSystem();
        String nameService = conf.get("dfs.nameservices");
        String hdfsRPCUrl = "hdfs://" + nameService + ":" + 8020;
        dfs.initialize(URI.create(hdfsRPCUrl), conf);
        if (dfs.exists(dst)) {
          dfs.delete(dst, true);
        }
        FileOutputFormat.setOutputPath(job, dst);
        // 提交 job
        System.exit(job.waitForCompletion(true) ? 0 : 1);
      }
    }
    
    

方式二

lambada 表达式 重写 compareTo 方法 借助 List 的 sorted 方法排序

  1. 编写 JavaBean

    package cn.lhz.hadoop.mapreduce.wordcount05;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    /**
     * @author 李昊哲
     * @version 1.0.0
     */
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Word {
      /**
       * 单词
       */
      private String name;
      /**
       * 单词数量
       */
      private int count;
    
    
      @Override
      public String toString() {
        return this.name + "\t" + this.count;
      }
    }
    
    
  2. 编写 Mapper 类

    package cn.lhz.hadoop.mapreduce.wordcount05;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    /**
     * @author 李昊哲
     * @version 1.0.0
     */
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Word {
      /**
       * 单词
       */
      private String name;
      /**
       * 单词数量
       */
      private int count;
    
    
      @Override
      public String toString() {
        return this.name + "\t" + this.count;
      }
    }
    
    
  3. 编写 Reducer 类

    package cn.lhz.hadoop.mapreduce.wordcount05;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    
    /**
     * reduce 阶段
     * Reduce<Text, IntWritable,Text,IntWritable> 中四个泛型 两个为一组
     * 前两个 LongWritable,Text 为 map 输出 reduce 输入 数据的类型,map 输出 reduce 输入 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     * 后两个 Text,IntWritable 为 reduce 输出数据的类型 ,reduce 输出 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
      private final List<Word> words = new ArrayList<Word>();
      private final Text text = new Text();
      private final IntWritable intWritable = new IntWritable();
    
      @Override
      protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        // 单词数量累加的和
        int count = 0;
        // 遍历迭代器
        for (IntWritable value : values) {
          // 单词标记累加得到单词数量
          count += value.get();
        }
        words.add(new Word(key.toString(), count));
      }
    
      @Override
      protected void cleanup(Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        // 排序
        List<Word> collect = words.stream().sorted((a, b) -> {
          // 降序
          int x = b.getCount() - a.getCount();
          if (x != 0) {
            return x;
          } else {
            return a.getName().compareTo(b.getName());
          }
        }).collect(Collectors.toList());
        // 遍历输出
        for (Word word : collect) {
          text.set(word.getName());
          intWritable.set(word.getCount());
          context.write(text, intWritable);
        }
    
      }
    }
    
    
  4. 编写 Job 类

    package cn.lhz.hadoop.mapreduce.wordcount05;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.hdfs.DistributedFileSystem;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    import java.net.URI;
    
    
    /**
     * 借助 List中的 sorted 方法实训排序
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountDriver {
    
      public static void main(String[] args) throws Exception {
        // 设置环境变量 hadoop 用户名 为 root
        System.setProperty("HADOOP_USER_NAME", "root");
    
        // 参数配置对象
        Configuration conf = new Configuration();
    
        // 跨平台提交
        conf.set("mapreduce.app-submission.cross-platform", "true");
    
        // 本地运行
        // conf.set("mapreduce.framework.name", "local");
    
        // 设置默认文件系统为 本地文件系统
        // conf.set("fs.defaultFS", "file:///");
    
        // 声明Job对象 就是一个应用
        Job job = Job.getInstance(conf, "word count");
    
        // 本地提交启用该行
        // job.setJar("F:\\新疆大学\\code\\bigdata2024\\bigdata\\hadoop\\target\\hadoop.jar");
    
        // 指定当前Job的驱动类
        job.setJarByClass(WordCountDriver.class);
    
        // 指定当前Job的 Mapper
        job.setMapperClass(WordCountMapper.class);
        // 指定当前Job的 Combiner 注意:一定不能影响最终计算结果 否则 不使用
        // job.setCombinerClass(WordCountReduce.class);
        // 指定当前Job的 Reducer
        job.setReducerClass(WordCountReduce.class);
    
        // 设置 map 输出 key 的数据类型
        job.setMapOutputValueClass(Text.class);
        // 设置 map 输出 value 的数据类型
        job.setMapOutputValueClass(IntWritable.class);
        // 设置 reduce 输出 key 的数据类型
        job.setOutputKeyClass(Text.class);
        // 设置 reduce 输出 value 的数据类型
        job.setOutputValueClass(IntWritable.class);
        // 定义 map 输入的路径 注意:该路径默认为hdfs路径
        FileInputFormat.addInputPath(job, new Path("/WordCount/input/wcdata.txt"));
        // 定义 reduce 输出数据持久化的路径 注意:该路径默认为hdfs路径
        Path dst = new Path("/WordCount/sort");
    
    //    FileSystem fs = FileSystem.get(conf);
    //    if (fs.exists(dst)) {
    //      fs.delete(dst, true);
    //    }
    
        DistributedFileSystem dfs = new DistributedFileSystem();
        String nameService = conf.get("dfs.nameservices");
        String hdfsRPCUrl = "hdfs://" + nameService + ":" + 8020;
        dfs.initialize(URI.create(hdfsRPCUrl), conf);
        if (dfs.exists(dst)) {
          dfs.delete(dst, true);
        }
        FileOutputFormat.setOutputPath(job, dst);
        // 提交 job
        System.exit(job.waitForCompletion(true) ? 0 : 1);
      }
    }
    
    

方式三

JavaBean 实现 Comparable 重写 compareTo 方法 借助TreeSet排序

  1. 编写 JavaBean

    package cn.lhz.hadoop.mapreduce.wordcount06;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    /**
     * @author 李昊哲
     * @version 1.0.0
     */
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Word implements Comparable<Word> {
      /**
       * 单词
       */
      private String name;
      /**
       * 单词数量
       */
      private int count;
    
    
      @Override
      public String toString() {
        return this.name + "\t" + this.count;
      }
    
      @Override
      public int compareTo(Word word) {
        // 按照单词数量降序
        int x = word.getCount() - this.count;
        if (x != 0) {
          return x;
        } else {
          // 如果单词数量相同 按照单词 hash 值 升序
          return this.name.compareTo(word.getName());
        }
      }
    }
    
    
  2. 编写 Mapper 类

    package cn.lhz.hadoop.mapreduce.wordcount06;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    /**
     * @author 李昊哲
     * @version 1.0.0
     */
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Word implements Comparable<Word> {
      /**
       * 单词
       */
      private String name;
      /**
       * 单词数量
       */
      private int count;
    
    
      @Override
      public String toString() {
        return this.name + "\t" + this.count;
      }
    
      @Override
      public int compareTo(Word word) {
        // 按照单词数量降序
        int x = word.getCount() - this.count;
        if (x != 0) {
          return x;
        } else {
          // 如果单词数量相同 按照单词 hash 值 升序
          return this.name.compareTo(word.getName());
        }
      }
    }
    
    
  3. 编写 Reducer 类

    package cn.lhz.hadoop.mapreduce.wordcount06;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    import java.util.Set;
    import java.util.TreeSet;
    
    /**
     * reduce 阶段
     * Reduce<Text, IntWritable,Text,IntWritable> 中四个泛型 两个为一组
     * 前两个 LongWritable,Text 为 map 输出 reduce 输入 数据的类型,map 输出 reduce 输入 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     * 后两个 Text,IntWritable 为 reduce 输出数据的类型 ,reduce 输出 是一个 key value 数据结构, Text 是 key 的数据类型,IntWritable 是 value 的数据类型
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
      private final Set<Word> words = new TreeSet<>();
      private final Text text = new Text();
      private final IntWritable intWritable = new IntWritable();
    
      @Override
      protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        // 单词数量累加的和
        int count = 0;
        // 遍历迭代器
        for (IntWritable value : values) {
          // 单词标记累加得到单词数量
          count += value.get();
        }
        words.add(new Word(key.toString(), count));
      }
    
      @Override
      protected void cleanup(Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        for (Word word : words) {
          text.set(word.toString());
          intWritable.set(word.getCount());
          context.write(text, intWritable);
        }
      }
    }
    
    
  4. 编写 Job 类

    package cn.lhz.hadoop.mapreduce.wordcount06;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.hdfs.DistributedFileSystem;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    import java.net.URI;
    
    
    /**
     * 借助 TreeSet 实训排序
     *
     * @author 李昊哲
     * @version 1.0.0
     */
    public class WordCountDriver {
    
      public static void main(String[] args) throws Exception {
        // 设置环境变量 hadoop 用户名 为 root
        System.setProperty("HADOOP_USER_NAME", "root");
    
        // 参数配置对象
        Configuration conf = new Configuration();
    
        // 跨平台提交
        conf.set("mapreduce.app-submission.cross-platform", "true");
    
        // 本地运行
        // conf.set("mapreduce.framework.name", "local");
    
        // 设置默认文件系统为 本地文件系统
        // conf.set("fs.defaultFS", "file:///");
    
        // 声明Job对象 就是一个应用
        Job job = Job.getInstance(conf, "word count");
    
        // 本地提交启用该行
        // job.setJar("F:\\新疆大学\\code\\bigdata2024\\bigdata\\hadoop\\target\\hadoop.jar");
    
        // 指定当前Job的驱动类
        job.setJarByClass(WordCountDriver.class);
    
        // 指定当前Job的 Mapper
        job.setMapperClass(WordCountMapper.class);
        // 指定当前Job的 Combiner 注意:一定不能影响最终计算结果 否则 不使用
        // job.setCombinerClass(WordCountReduce.class);
        // 指定当前Job的 Reducer
        job.setReducerClass(WordCountReduce.class);
    
        // 设置 map 输出 key 的数据类型
        job.setMapOutputValueClass(Text.class);
        // 设置 map 输出 value 的数据类型
        job.setMapOutputValueClass(IntWritable.class);
        // 设置 reduce 输出 key 的数据类型
        job.setOutputKeyClass(Text.class);
        // 设置 reduce 输出 value 的数据类型
        job.setOutputValueClass(IntWritable.class);
        // 定义 map 输入的路径 注意:该路径默认为hdfs路径
        FileInputFormat.addInputPath(job, new Path("/WordCount/input/wcdata.txt"));
        // 定义 reduce 输出数据持久化的路径 注意:该路径默认为hdfs路径
        Path dst = new Path("/WordCount/sort");
    
    //    FileSystem fs = FileSystem.get(conf);
    //    if (fs.exists(dst)) {
    //      fs.delete(dst, true);
    //    }
    
        DistributedFileSystem dfs = new DistributedFileSystem();
        String nameService = conf.get("dfs.nameservices");
        String hdfsRPCUrl = "hdfs://" + nameService + ":" + 8020;
        dfs.initialize(URI.create(hdfsRPCUrl), conf);
        if (dfs.exists(dst)) {
          dfs.delete(dst, true);
        }
        FileOutputFormat.setOutputPath(job, dst);
        // 提交 job
        System.exit(job.waitForCompletion(true) ? 0 : 1);
      }
    }
    
    
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MapReduce中,排序是非常重要的。MapReduce在Map和Reduce的两个阶段中都会执行排序操作。全局排序是指在一个MapReduce程序产生的输出文件中,所有的结果都是按照某个策略进行排序的,例如降序还是升序。在全局排序中,只有一个reduce任务可以保证数据的全局有序,但这样无法充分利用Hadoop集群的优势。 在MapReduce的shuffle过程中,通常会执行多次排序。首先是在Map输出阶段,根据分区和key进行快速排序。然后,在Map的合并溢写文件阶段,将同一个分区的多个溢写文件进行归并排序,合成一个大的溢写文件。最后,在Reduce输入阶段,将同一分区来自不同Map任务的数据文件进行归并排序。最后阶段使用了堆排作为最后的合并过程。 在MapReduce中,有两种排序方式,即快速排序和归并排序。快速排序是通过一趟排序将要排序的数据分割成独立的两部分,然后对这两部分数据分别进行快速排序,最终达到整个数据变成有序序列的目的。归并排序是建立在归并操作上的一种排序算法,通过将已有序的子序列合并,得到完全有序的序列。归并排序可以采用分治法的方式进行,将子序列逐步合并,最终得到整个序列的有序结果。 因此,MapReduce中的排序操作是通过多次排序和归并的方式实现的,以确保数据的有序性。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昊哲小课

桃李不言下自成蹊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值