大数据学习(四)-用MapReduce实现表关联

前言

前面使用MapReduce,可以进行单词计数,单词去重,数字排序等,那么结合到数据库应用,
如何实现表关联呢?
MapReduce更像算法题,怎么通过Map和Reduce这两个步骤来实现关联,得到所需数据呢?
例如有一张表,里面两个字段,child和parent,现在让你找出里面的grandChild和grandParent来。
以MySQL为例,我们直接一行sql就可以解决:

select a.child,b.parent 
from child_parent a, child_parent b
where a.parent=b.child
order by a.child desc

那么从MapReduce角度该如何设计Map以及Reduce函数呢?

设计

  1. 需要使得左表的parent和右表的child列相连接。
  2. 将paren设置为key,而child作为value进行输出,作为左表
  3. 再将同一对child和paren的child设为key,而parent设置为value作为输出。
  4. 给每个输出增加标志作为区分左右表。
  5. 在Reduce函数的接受的结果中,每个key的value-list包含了grandchild和grandparen关系
  6. 取出每个key的value进行解析,将左表的child放到一个数组,右表的parent放到一个数组,最后做双重循环迪卡尔集即可(就如sql语句中的笛卡尔集)
  7. 因为在Reduce中,给出的是key相同的value_list,所以就是相当于上面sql的where a.parent=b.child

具体实现

package com.anla.chapter3.innerjoin;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
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;
import java.util.Iterator;

/**
 * @user anLA7856
 * @time 19-3-22 下午6:01
 * @description
 */
public class SimpleJoin {
    public static int time = 0;

    public static class Map extends Mapper<Object, Text, Text, Text> {
        @Override
        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String childName;
            String parentName;
            String relationType;
            String line = value.toString();
            int i = 0;
            // 用来寻找分隔符
            String[] values = line.split(" ");
            if (!"child".equals(values[0])) {
                // 不为child,即不计算第一行
                childName = values[0];
                parentName = values[1];
                relationType = "1";    // 左右表区分
                context.write(new Text(parentName), new Text(relationType+"+"+childName+"+"+parentName));   // 左表
                relationType = "2";    // 左右表区分
                context.write(new Text(childName), new Text(relationType+"+" + childName + "+" +parentName));   // 右表
            }
        }
    }

    public static class Reduce extends Reducer<Text, Text, Text, Text> {
        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            if (time == 0) {   // 输出表头
                context.write(new Text("grandChild"), new Text("grandParent"));
                time ++;
            }
            int grandChildNum = 0;
            String grandChild[] = new String[10];
            int grandParentNum = 0;
            String grandParent[] = new String[10];
            Iterator iterator = values.iterator();
            while (iterator.hasNext()){
                String record = iterator.next().toString();
                int len = record.length();
                if (len == 0) {
                    continue;
                }
                char relationType = record.charAt(0);
                String childName = record.split("\\+")[1];
                String parentName = record.split("\\+")[2];
                // 左表
                if (relationType == '1') {
                    grandChild[grandChildNum] = childName;
                    grandChildNum ++;
                }else {
                    grandParent[grandParentNum] = parentName;
                    grandParentNum++;
                }

            }
            // grandChild和grandParent求迪卡尔
            if (grandChildNum != 0 && grandParentNum != 0) {
                for (int m = 0; m <grandChildNum; m++) {
                    for (int n = 0; n < grandParentNum; n++){
                        context.write(new Text(grandChild[m]), new Text(grandParent[n]));
                    }
                }
            }
        }

    }


    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, "SimpleJoin");
        job.setJarByClass(SimpleJoin.class);
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.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
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值