MapReduce Join

1. MapReduce Join

1.1 Join

join 常使用在数据库中,例如内连接、外连接。在大数据应用中,MapReduce Join 能够解决数据的连接问题。

1.2 MapReduce Join 的分类

Join 实现的方法有两种:Reduce Join、Map Join

🌟 Reduce Join:

  1. Map端:为不同文件的 key/value 打上标签来区分,用连接的字段作为key,value可以用当前行的所有内容,并且为value添加标识。
  2. reduce端:获取来在map处理后的不同文件的 key/value 对,根据标识获取字段,最后将不同文件的字段合并。

🌟 Map Join:

  1. map join 适用于一张表十分小、一张表十分大的场景,能够尽可能地减少数据倾斜。
  2. 实现方法:再提交作业时,先将小表文件放到作业的 DistributedCache中,然后从 DistributedCache 中取出该小表,并进行 join 操作;扫描大表,查看大表中每条记录的 join key/value 能否再内存中找到相同的 join key 的记录,如果有则输出。

1.3 DistributedCache 分布式缓存

🌟 数据倾斜原因:
如果是多张表的操作都是在reduce阶段完成,reduce端的处理压 力太大, map节点的运算负载则很低,资源利用率不高,且在reduce阶段 极易产生 数据倾斜。

实操案例:
reduce端表合并(数据倾斜)

解决方案:
在map端缓存多张表,提前处理业务逻辑,这样增加map端业务, 减少reduce端数据的压力,尽可能的减少数据倾斜。

具体办法:

采用 DistributedCache,在mapper的setup阶段,将文件读取到缓存集合中
在驱动函数中加载缓存。

实操案例:
map端表合并(DistributedCache)

2. Join 简单实现

案例实现:将学生表和成绩表连接。

2.1 数据表

学生表:student.txt,学生表中提供了一个成表中不存在成绩的学生

01 赵雷 1990-01-01 男
02 钱电 1990-12-21 男
03 孙风 1990-12-20 男 
04 李云 1990-12-06 男
05 周梅 1991-12-01 女
06 吴兰 1992-01-01 女

成绩表:score.txt,学生 ID 被放在的第二位

01 01 80
02 01 90
03 01 99
01 02 70
02 02 60
03 02 80
01 03 80
02 03 80
03 03 80
01 04 50
02 04 30
03 04 20
01 05 76
02 05 87

2.2 实现

Mapper、Reducer、Driver如下:

public class Job_JoinDriver {

    // Mapper
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        job.setJarByClass(Job_JoinDriver.class);
        job.setMapperClass(Job_JoinMapper.class);
        job.setReducerClass(Job_JoinReducer.class);

        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

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

    static class Job_JoinMapper extends Mapper<LongWritable, Text, Text, Text> {

        Text k = new Text();
        Text v = new Text();

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

            // 通过切片获取到当前读取文件的文件名
            InputSplit inputSplit = context.getInputSplit();
            FileSplit fileSplit = (FileSplit) inputSplit;
            String path = fileSplit.getPath().getName();

            // 定义 sid 用于存放获取的 学生ID
            String sid;

            String[] split = value.toString().split("\\s+");

            // 判断文件名
            if (path.startsWith("student")) {
                // 学生表的 ID 在第一位
                sid = split[0];
                // 将整条数据作为 vlaue,并添加 Stu 的标识
                v.set("Stu" + value);
            } else {
                // 成绩表的 ID 在第二位
                sid = split[1];
                // 将整条数据作为 vlaue,并添加 Sco 的标识
                v.set("Sco" + value);
            }

            k.set(sid);
            context.write(k, v);
        }
    }

    static class Job_JoinReducer extends Reducer<Text, Text, Text, Text> {
        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            // 用于存放获取到的学生信息
            String stuContext = "";
            // 用于存放学生的各科成绩
            LinkedList<String> scoContext = new LinkedList<>();

            for (Text value : values) {
                String res = value.toString();
                // 根据添加的标识,来区分学生信息和成绩
                if (res.startsWith("Stu")){
                    stuContext = res.substring(3);
                } else {
                    scoContext.add(res.substring(3));
                }
            }

            for (String score : scoContext) {
                // 将学生成绩与学生信息拼接
                Text v = new Text(stuContext + "  " + score);
                context.write(key, v);
            }
        }
    }
}

📤 查看输出:

image-20211129105155118

🌈 如上只是简单的拼接,输出结果可以再优化!

3. 写在最后

实例中是实现的 join,就是通过打标识、取标识,实现对不同文件数据的区分。

 


❤️ END ❤️
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JOEL-T99

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值