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

来源:互联网 发布:上海软件定制开发 编辑:程序博客网 时间:2024/06/05 17:32

这里用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,11002,20170710,P0001,31003,20170710,P0002,31004,20170710,P0002,4[root@mini3 ~]# vi product.data P0001,xiaomiP0002,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-000001001,20170710,P0001,1   xiaomi1002,20170710,P0001,3   xiaomi1003,20170710,P0002,3   huawei1004,20170710,P0002,4   huawei
阅读全文
0 0
原创粉丝点击