Map端的Join map-side join

  • map-side join:(最为高效)
  • 核心思想:将小表进行分布式缓存,在map-task阶段读取缓存文件数据存储到内存数据结构中,以供reduce阶段连接查找。
  • 适用场景:有一个或者多个小表(文件)
  • 优点:将小表缓存,可以高效查询;由于在map阶段进行连接,所以将会大大减小map到reduce端的数据传输,从而减少不必要的shuffle耗时,提高整个mr的执行效率
  • 缺点:如果业务全是大表不适合
  • semi-join(半连接):
  • 核心思想:将大表过滤或者清洗后进行缓存,从而转换为map-side端的join。

导入的包 注意导入长包
以及数据 对应三个文件

/**
 * 作者:Shishuai
 * 文件名:MapSideJoinDemo
 * 时间:2019/9/4 19:11
 */

package com.mapjoin_reducejoin;

import ali.mr.day02.MapSideJoin;
import jdk.nashorn.internal.ir.BaseNode;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.filecache.DistributedCache;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.jboss.netty.util.internal.ConcurrentHashMap;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

/**
 * map-side join:(最为高效)
 * 核心思想:将小表进行分布式缓存,在map-task阶段读取缓存文件数据存储到内存数据结构中,以供reduce阶段连接查找。
 * 适用场景:有一个或者多个小表(文件)
 * 优点:将小表缓存,可以高效查询;由于在map阶段进行连接,所以将会大大减小map到reduce端的数据传输,从而减少不必要的shuffle耗时,提高整个mr的执行效率
 * 缺点:如果业务全是大表不适合
 *
 * semi-join(半连接):
 * 核心思想:将大表过滤或者清洗后进行缓存,从而转换为map-side端的join。
 *
 * login:
 uid	sexid	logindate
 1	1	2017-04-17 08:16:20
 2   2	2017-04-15 06:18:20
 3   1	2017-04-16 05:16:24
 4   2	2017-04-14 03:18:20
 5   1	2017-04-13 02:16:25
 6   2	2017-04-13 01:15:20
 7   1	2017-04-12 08:16:34
 8   2	2017-04-11 09:16:20
 9   0	2017-04-10 05:16:50

 sex:sexMap
 0	不知道
 1	男
 2	女

 user uname
 1	小红
 2   小行
 3   小通
 4   小闪
 5   小镇
 6   小振
 7   小秀
 8   小微
 9   小懂
 10	小明
 11  小刚
 12  小举
 13  小黑
 14  小白
 15  小鹏
 16  小习

 输出:
loginuid	sex		uname	logindate
 1	男	小红	2017-04-17 08:16:20
 2	女	小行	2017-04-15 06:18:20
 3	男	小通	2017-04-16 05:16:24
 4	女	小闪	2017-04-14 03:18:20
 5	男	小镇	2017-04-13 02:16:25
 6	女	小振	2017-04-13 01:15:20
 7	男	小秀	2017-04-12 08:16:34
 8	女	小微	2017-04-11 09:16:20
 9	不知道	小懂	2017-04-10 05:16:50

 *
 *
 * @Author Shishuai
 * @Email 1198319583@qq.com
 * @Description //TODO
 * @Date 19:39 2019/9/4
 * @Param
 * @Retrun 这个打包到集群上运行 两个表ur sex 以及login已经上传到hdfs 而且使用的是ha模式 我的端口是默认8020没改 改过的一般是9000
 **/

主要的一个setup和一个map函数
在setup 读取缓存文件 就是两个小表 ur 和 sex 因为就两列 读出来数据存到map中
在map 一行一行的读取login数据,切割后得到id
然后根据id取出对应map的值

public class MapSideJoinDemo {
    //自定义的mapper类
    public static class MyMapper extends Mapper<LongWritable, Text, Text, NullWritable>{

        public Text k = new Text();
        //读取缓存文件,并按照文件名称读取到map或者别的数据结构中
        //定义一个存储sex缓存的数据结构
        Map<String, String> sexMap = new ConcurrentHashMap<String, String>();
        Map<String, String> userMap = new ConcurrentHashMap<String, String>();
        //读取缓存在hdfs上的两个表文件
        //找到这两个缓存文件 将他们放入map中 因为就两列 所以
        @Override
        protected void setup(Context context) throws IOException, InterruptedException {
            Path[] paths = DistributedCache.getLocalCacheFiles(context.getConfiguration());
            for(Path p : paths){
                String fileName = p.getName();
                BufferedReader bufferedReader = null;
                if(fileName.endsWith("sex")){
                    bufferedReader = new BufferedReader(new FileReader(new File(p.toString())));
                    while(bufferedReader.ready()){
                        String line = bufferedReader.readLine();
                        String sexs[] = line.split("\t");
                        sexMap.put(sexs[0], sexs[1]);
                    }
                }else if(fileName.equals("ur")){
                    bufferedReader = new BufferedReader(new FileReader(new File(p.toString())));
                    while(bufferedReader.ready()){
                        String line = bufferedReader.readLine();
                        String users[] = line.split("\t");
                        userMap.put(users[0], users[1]);
                    }
                }
                if(bufferedReader != null){
                    bufferedReader.close();
                }
            }

        }
        //抽象map函数   (map阶段的核心业务逻辑)
        //然后进行map过程 一行一行读入login表中的信息
        //uid  sexid   time
        //1	   1	 2017-04-17 08:16:20  比如读入这个 切割后根据前边两个id去拿两个map对应的值
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String[] words = value.toString().split("\t");
            String uid = words[0];
            String sex_id = words[1];
            String uname = "";
            String sexlab = "";
            sexlab = sexMap.getOrDefault(sex_id, "");
            uname = userMap.getOrDefault(uid, "");
            this.k.set(uid + "\t" + sexlab + "\t" + uname + "\t" + words[2]);
            context.write(k, NullWritable.get());

        }
    }
    //驱动方法
    public static void main(String[] args) {


        try {
            //1、获取配置对象并进行属性设置
            Configuration conf = new Configuration();

            //对conf设置
            conf.set("fs.defaultFS", "hdfs://qf");
            conf.set("dfs.nameservices", "qf");
            conf.set("dfs.ha.namenodes.qf", "nn1, nn2");
            conf.set("dfs.namenode.rpc-address.qf.nn1", "hadoop01:8020");
            conf.set("dfs.namenode.rpc-address.qf.nn2", "hadoop02:8020");
            conf.set("dfs.client.failover.proxy.provider.qf", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");


            //2、获取job
            Job job = Job.getInstance(conf, "mapSideJoin");
            //3、对job设置运行主类
            job.setJarByClass(MapSideJoinDemo.class);
            //4、对job的map端属性设置
            job.setMapperClass(MyMapper.class);
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(NullWritable.class);

            //设置缓存 (缓存文件读取不了)
            //job.setCacheFiles();
            job.addCacheFile(new URI("hdfs://qf:8020/sex"));
            job.addCacheFile(new URI("hdfs://qf:8020/ur"));
            //6、设置job的输入路径和输出路径
            FileInputFormat.addInputPath(job, new Path(args[0]));
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
            //7、提交作业
            int success = job.waitForCompletion(true) ? 0 : 1;
            //8、退出
            System.exit(success);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

[root@hadoop01 join]# yarn jar /home/hadoopDemo-1.0-SNAPSHOT.jar com.mapjoin_reducejoin.MapSideJoinDemo /login /out/03

结果文件 没问题
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值