Mapreduce中的DistributedCache应用-解决join算法中数据倾斜问题

这里用DistributedCache(分布式缓存)来解决join算法实现中的数据倾斜问题,同样考虑那篇博文的两张表,订单表和产品表(需求就是根据外键商品id来将两张表信息合并)。
订单号 时间 商品id 购买数量
1001,20170710,P0001,1
1002,20170710,P0001,3
1003,20170710,P0002,3
1004,20170710,P0002,4

商品id 商品名称
P0001,xiaomi
P0002,huawei

拼接成
1001 ,20170710,P0001,1 xiaomi
1002,20170710,P0001,3 xiaomi
1003,20170710,P0002,3,huawei
1004,20170710,P0002,4,huawei
考虑问题:在前面博文的mapreduce程序中,如果某些产品非常畅销,肯定会产生很多订单,但是刚好这些订单信息都传到了一个reduce中(分区默认就是使用hashcode%reducetask数量,所以这种情况是正常的)。那么这个reducetask压力就很大了,而其他的reducetask处理的信息就很小,有的甚至就处理几条数据,这就出现了数据倾斜问题。

解决方案:一般来说订单表的数据远远多于产品表数据,毕竟产品的种类就那些,所以我们可以把产品信息都交给maptask就行了逻辑都让maptask来处理,也就是说不使用reduce了,而让每个maptask持有个product.data(存储产品信息的文件)即可。那么maptask怎么获得这个文件呢?刚好hadoop提供了DistributedCache,我们将文件交给这个分布式缓存,它会将我们的文件放到maptask的工作目录中,那么map端可以直接从工作目录中去拿。
实现:

public class MapJoin {
    static class MapJoinMapper extends Mapper<LongWritable, Text, Text, NullWritable>{
        //用来缓存小文件(商品文件中的数据)
        Map<String, String> produceMap = new HashMap<String,String>();
        Text k = new Text();
        /*
         * 源码中能看到在循环执行map()之前会执行一次setUp方法,可以用来做初始化
         */
        @Override
        protected void setup(Context context)
                throws IOException, InterruptedException {
            //将商品文件中的数据写到缓存中  千万别写成/product.data否则会提示找不到该文件
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("product.data")));
            String line = null;
            while((line=br.readLine())!=null){
                //一行数据格式为P0001,xiaomi(商品id,商品名称)
                String[] fields = line.split(",");
                produceMap.put(fields[0], fields[1]);
            }
        }
        @Override
        protected void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            //一行订单数据    格式为 1001,20170710,P0001,1(订单id,创建时间,商品id,购买商品数量)
            String line = value.toString();
            String[] fields = line.split(",");
            //根据订单数据中商品id在缓存中找出来对应商品信息(商品名称),进行串接
            String productName = produceMap.get(fields[2]);
            k.set(line+"\t"+productName);
            context.write(k, NullWritable.get());
        }
    }
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        //jar包位置
        job.setJarByClass(MapJoin.class);

        job.setMapperClass(MapJoinMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(NullWritable.class);
        //设置最终输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        //指定需要缓存一个文件到所有的maptask运行节点工作目录
//      job.addArchiveToClassPath(archive);缓存jar包到task运行节点的classpath中
//      job.addCacheArchive(uri);缓存压缩包到task运行节点的工作目录
//      job.addFileToClassPath(file);//缓存普通文件到task运行节点的classpath中

        //将产品表文件缓存到task工作节点的工作目录中去
        //缓存普通文件到task运行节点的工作目录(hadoop帮我们完成)
        job.addCacheFile(new URI("hdfs://192.168.25.127:9000/mapjoincache/product.data"));

        //不需要reduce,那么也就没有了shuffle过程
        job.setNumReduceTasks(0);

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

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

测试:
将工程打包上传到集群中去
创建两个订单文件和产品文件(orders.data和product.data,内容就是上面的内容)
创建输入目录/mapjoincache/input,将orders.data传上去
将产品文件放到/mapjoincache下。
运行程序

[root@mini3 ~]# vi orders.data 
1001,20170710,P0001,1
1002,20170710,P0001,3
1003,20170710,P0002,3
1004,20170710,P0002,4
[root@mini3 ~]# vi product.data 
P0001,xiaomi
P0002,huawei
[root@mini3 ~]# hadoop fs -mkdir -p /mapjoincache/input
[root@mini3 ~]# hadoop fs -put orders.data /mapjoincache/input
[root@mini3 ~]# hadoop fs -put product.data /mapjoincache
[root@mini3 ~]# hadoop jar mapjoin.jar com.scu.hadoop.rmapjoin.MapJoin /mapjoincache/input /mapjoincache/output
[root@mini3 ~]# hadoop fs -ls /mapjoincache/output/
Found 2 items
-rw-r--r--   2 root supergroup          0 2017-10-16 21:16 /mapjoincache/output/_SUCCESS
-rw-r--r--   2 root supergroup        116 2017-10-16 21:16 /mapjoincache/output/part-m-00000

[root@mini3 ~]# hadoop fs -cat /mapjoincache/output/part-m-00000
1001,20170710,P0001,1   xiaomi
1002,20170710,P0001,3   xiaomi
1003,20170710,P0002,3   huawei
1004,20170710,P0002,4   huawei
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值