一、实战概述

  • 在信息爆炸的时代,数据处理与分析的重要性日益凸显。MapReduce作为一种强大的分布式计算模型,以其高效并行处理能力解决了大规模数据集的处理难题。本次实践教程,我们将通过一个具体的任务——学生信息排序,深入浅出地引导大家掌握MapReduce的基本原理和应用。从数据准备到实现步骤,再到拓展练习,我们将一起领略MapReduce的强大魅力,揭示其在大数据处理中的关键作用。

  • 本教程将通过Hadoop MapReduce实现学生信息排序任务。首先,启动Hadoop服务,创建sortstudent目录和包含学生信息的student.txt文件,然后将其上传到HDFS的/sortstudent/input目录。接着,创建Maven项目SortStudent,添加hadoopjunit依赖,配置日志属性文件。在net.hw.mr包下创建Student类实现序列化比较接口,设置性别升序、年龄降序的比较规则。随后,创建StudentMapperStudentReducer类进行数据处理和排序。在StudentDriver类中设置作业配置并运行。拓展练习中,我们将修改Student类的比较规则以实现性别升序、年龄降序排序,最后重新运行StudentDriver查看结果。

二、提出任务

  • 学生表,包含五个字段(姓名、性别、年龄、手机、专业),有8条记录
姓名 性别 年龄 手机 专业
李文丽 19 15892943440 大数据应用
张三丰 20 15890903456 人工智能应用
郑晓琳 18 18867890234 软件技术
唐宇航 22 15856577890 计算机应用
陈燕文 21 13956576783 软件技术
童安格 19 15889667890 大数据应用
肖雨涵 20 15857893452 软件技术
冯晓华 18 18856784560 大数据应用
  • 使用MR计算框架,学生信息按年龄降序排列结果
    在这里插入图片描述

三、完成任务

(一)准备数据

1、在虚拟机上创建文本文件

  • 在master虚拟机上创建student.txt文件
    在这里插入图片描述

2、上传文件到HDFS指定目录

  • 创建/sortstudent/input目录,执行命令:hdfs dfs -mkdir -p /sortstudent/input
    在这里插入图片描述

  • 将文本文件student.txt上传到HDFS的/sortstudent/input目录
    在这里插入图片描述

(二)实现步骤

  • 说明:集成开发环境IntelliJ IDEA版本 - 2022.3

1、创建Maven项目

  • Maven项目 - MRSortStudent,设置了JDK版本 - 1.8,组标识 - net.huawei.mr
    在这里插入图片描述
  • 单击【Create】按钮,得到初始化项目
    在这里插入图片描述

2、添加相关依赖

  • pom.xml文件里添加hadoopjunit依赖
    在这里插入图片描述
<dependencies>                                      
    <!--hadoop客户端-->                                
    <dependency>                                    
        <groupId>org.apache.hadoop</groupId>        
        <artifactId>hadoop-client</artifactId>      
        <version>3.3.4</version>                    
    </dependency>                                   
    <!--单元测试框架-->                                   
    <dependency>                                    
        <groupId>junit</groupId>                    
        <artifactId>junit</artifactId>              
        <version>4.13.2</version>                   
    </dependency>                                   
</dependencies>                                     
  • 刷新项目依赖
    在这里插入图片描述

3、创建日志属性文件

  • resources目录里创建log4j.properties文件
    在这里插入图片描述
log4j.rootLogger=ERROR, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/sortstudent.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

4、创建学生实体类

  • 创建net.huawei.mr包,在包里创建Student
    在这里插入图片描述

  • 为了让学生按照年龄排序,需要让学生实体类实现一个序列化可比较接口 - WritableComparable,这个接口有三个抽象方法要我们去实现。

  • 查看WritableComparable接口的继承关系图
    在这里插入图片描述

  • 实现WritableComparable接口
    在这里插入图片描述

package net.huawei.mr;

import org.apache.hadoop.io.WritableComparable;

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

/**
 * 功能:学生实体类
 * 作者:华卫
 * 日期:2023年12月29日
 */
public class Student implements WritableComparable<Student> {
    private String name;
    private String gender;
    private int age;
    private String phone;
    private String major;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                ", major='" + major + '\'' +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        // 按年龄降序排列
        return o.getAge() - this.getAge();
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(name);
        out.writeUTF(gender);
        out.writeInt(age);
        out.writeUTF(phone);
        out.writeUTF(major);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        name = in.readUTF();
        gender = in.readUTF();
        age = in.readInt();
        phone = in.readUTF();
        major = in.readUTF();
    }
}
  • 说明:该Java类Student表示学生对象,实现WritableComparable接口以供Hadoop处理。它包含姓名、性别、年龄、电话和专业属性的getter和setter方法。compareTo方法用于按年龄降序比较学生对象。write和readFields方法实现了序列化与反序列化,使得Student对象可在Hadoop数据流中读写传输。

5、创建学生映射器类

  • net.huawei.mr里创建StudentMapper
    在这里插入图片描述
package net.huawei.mr;

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;

/**
 * 功能:学生映射器类
 * 作者:华卫
 * 日期:2023年12月29日
 */
public class StudentMapper extends Mapper<LongWritable, Text, Student, NullWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        // 获取行数据
        String line = value.toString();
        // 按空格拆分得到字段数组
        String[] fields = line.split(" ");
        // 获取学生信息
        String name = fields[0];
        String gender = fields[1];
        int age = Integer.parseInt(fields[2]);
        String phone = fields[3];
        String major = fields[4];
        // 创建学生对象
        Student student = new Student();
        // 设置学生对象属性
        student.setName(name);
        student.setGender(gender);
        student.setAge(age);
        student.setPhone(phone);
        student.setMajor(major);
        // 将<student,null>键值对写入中间结果
        context.write(student, NullWritable.get());
    }
}
  • 说明:该Java类StudentMapper是Hadoop MapReduce作业的映射器,用于处理学生信息文本数据。它从输入行中解析出学生各项属性,并封装成Student对象student,然后将<student,null>键值对写入中间结果,以供后续Reducer阶段进一步处理。

6、创建学生归并器类

  • net.huawei.mr包里创建StudentReducer
    在这里插入图片描述
package net.huawei.mr;

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

import java.io.IOException;

/**
 * 功能:学生归并器类
 * 作者:华卫
 * 日期:2023年12月29日
 */
public class StudentReducer extends Reducer<Student, NullWritable, Text, NullWritable> {
    @Override
    protected void reduce(Student key, Iterable<NullWritable> values, Context context)
            throws IOException, InterruptedException {
        // 获取学生对象
        Student student = key;
        // 拼接学生信息
        String studentInfo = student.getName() + "\t"
                + student.getGender() + "\t"
                + student.getAge() + "\t"
                + student.getPhone() + "\t"
                + student.getMajor();
        // 将键值对<studentInfo,null>写入结果文件
        context.write(new Text(studentInfo), NullWritable.get());
    }
}
  • 说明:该Java类StudentReducer是Hadoop MapReduce的归并器,继承自Reducer。在reduce方法中,获取学生对象并拼接其各项属性信息为字符串studentInfo,然后将<studentInfo,null>键值对写入输出文件,实现对学生数据的收集与整合。

7、创建学生驱动器类

  • net.huawei.mr包里创建StudentDriver
    在这里插入图片描述
package net.huawei.mr;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
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;

/**
 * 功能:学生驱动器类
 * 作者:华卫
 * 日期:2023年12月29日
 */
public class StudentDriver {
    public static void main(String[] args) throws Exception {
        // 创建配置对象
        Configuration conf = new Configuration();
        // 设置客户端使用数据节点主机名属性
        conf.set("dfs.client.use.datanode.hostname", "true");

        // 获取作业实例
        Job job = Job.getInstance(conf);
        // 设置作业启动类
        job.setJarByClass(StudentDriver.class);

        // 设置Mapper类
        job.setMapperClass(StudentMapper.class);
        // 设置map任务输出键类型
        job.setMapOutputKeyClass(Student.class);
        // 设置map任务输出值类型
        job.setMapOutputValueClass(NullWritable.class);

        // 设置Reducer类
//        job.setReducerClass(StudentReducer.class);
//        // 设置reduce任务输出键类型
//        job.setOutputKeyClass(Text.class);
//        // 设置reduce任务输出值类型
//        job.setOutputValueClass(NullWritable.class);

        // 定义uri字符串
        String uri = "hdfs://master:9000";

        // 创建输入目录
        Path inputPath = new Path(uri + "/sortstudent/input");
        // 创建输出目录
        Path outputPath = new Path(uri + "/sortstudent/output");

        // 获取文件系统
        FileSystem fs = FileSystem.get(new URI(uri), conf);
        // 删除输出目录(第二个参数设置是否递归)
        fs.delete(outputPath, true);

        // 给作业添加输入目录(允许多个)
        FileInputFormat.addInputPath(job, inputPath);
        // 给作业设置输出目录(只能一个)
        FileOutputFormat.setOutputPath(job, outputPath);

        // 等待作业完成
        job.waitForCompletion(true);

        // 输出统计结果
        System.out.println("======统计结果======");
        FileStatus[] fileStatuses = fs.listStatus(outputPath);
        for (int i = 1; i < fileStatuses.length; i++) {
            // 输出结果文件路径
            System.out.println(fileStatuses[i].getPath());
            // 获取文件系统数据字节输入流
            FSDataInputStream in = fs.open(fileStatuses[i].getPath());
            // 将结果文件显示在控制台
            IOUtils.copyBytes(in, System.out, 4096, false);
        }
    }
}
  • 注意:暂时将Reducer类的设置注释掉

8、启动应用,查看结果

  • 运行StudentDriver 类,看到输出的学生对象确实按按年龄降序排列
    在这里插入图片描述
  • 恢复对Reducer类的设置
    在这里插入图片描述
  • 运行StudentDriver 类,输出格式没问题,学生信息也按年龄降序排列了
    在这里插入图片描述
  • 但是做了一件我们不需要的去重,少了3条记录,那就需要修改学生归并器代码

9、修改学生归并器类

  • 修改学生归并器类,遍历值迭代器,这样就不会按“年龄”去重了
    在这里插入图片描述

10、启动应用,查看结果

  • 运行StudentDriver 类,结果符合要求
    在这里插入图片描述

四、拓展练习

任务1:学生信息按年龄升序排列

  • 运行结果,如下图所示
    在这里插入图片描述

任务2:学生信息排序,先按性别升序,再按年龄降序

  • 运行结果,如下图所示
    在这里插入图片描述
Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐