MapReduce实战案例2 mapjoin

1.使用场景

适用于一张表十分小、一张表很大的场景。

2.优点

思考:在Reduce端处理过多的表,非常容易产生数据倾斜。怎么办?
在Map端缓存多张表,提前处理业务逻辑,这样增加Map端业务,减少Reduce端数据的压力,尽可能的减少数据倾斜。

3.具体步骤
  • 在Mapper的setup阶段,将文件读取到缓存集合中。
  • 在驱动函数中加载缓存。
4.需求

表4-4 订单数据表t_order

idpidamount
1001011
1002022
1003033
1004014
1005025
1006036

表4-5 商品信息表t_product

pidpname
01小米
02华为
03格力

表4-6 最终数据形式

idpnameamount
1001小米1
1004小米4
1002华为2
1005华为5
1003格力3
1006格力6
5.代码实现
1.bean对象
package com.zj.practice.mapreduce09.order_map_join;

import org.apache.hadoop.io.Writable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class order_MapJoin_Bean implements Writable {
    /**
     * 订单id
     */
    private String orderId;
    /**
     * 产品id
     */
    private String productId;
    /**
     * 商品名称
     */
    private String productName;
    /**
     * 商品数量
     */
    private int amount;

    public order_MapJoin_Bean() {
        super();
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return orderId + "\t" + productName + "\t" + amount;
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeUTF(orderId);
        dataOutput.writeUTF(productId);
        dataOutput.writeUTF(productName);
        dataOutput.writeInt(amount);
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        orderId = dataInput.readUTF();
        productId = dataInput.readUTF();
        productName = dataInput.readUTF();
        amount = dataInput.readInt();
    }
}
2.mapper端
package com.zj.practice.mapreduce09.order_map_join;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.HashMap;

/**
 * 思考:在Reduce端处理过多的表,非常容易产生数据倾斜。怎么办?
 * 在Map端缓存多张表,提前处理业务逻辑,这样增加Map端业务,减少Reduce端数据的压力,尽可能的减少数据倾斜。
 * 具体办法:采用DistributedCache
 * (1)在Mapper的setup阶段,将文件读取到缓存集合中。
 * (2)在驱动函数中加载缓存。
 * 缓存普通文件到Task运行节点。
 * job.addCacheFile(new URI("file:///e:/cache/pd.txt"));
 */

public class order_MapJoin_Mapper extends Mapper<LongWritable, Text, order_MapJoin_Bean, NullWritable> {
    // 存放小表数据 --> pdid,pdname
    private HashMap<String, String> hashMap = new HashMap<>();
    // 输出的Bean对象
    private order_MapJoin_Bean orderBean = new order_MapJoin_Bean();

    // 1.获取缓存的小表数据
    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        System.out.println("maptask开始执行");
        // 获取缓存的uri数组
        URI[] cacheFiles = context.getCacheFiles();
        // 这里只有一个小表,所以放在0号位置
        // 获取小表的路径
        String smallPath = cacheFiles[0].getPath().toString();
        // 读取小表数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(smallPath)));
        // 一次读取一行数据
        String line;
        while (StringUtils.isNotEmpty(line = bufferedReader.readLine())) {
            // 分隔字符串
            String[] split = line.split("\t");
            // 将0号元素-->pid作为key,1号元素-->pname作为value存储在hashmap中
            hashMap.put(split[0], split[1]);
        }
    }

    // 2.读取大表数据
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // 获取大表数据
        String line = value.toString();
        // 分隔字符串
        String[] split = line.split("\t");
        // 为bean对象赋值
        orderBean.setOrderId(split[0]);
        orderBean.setProductId(split[1]);
        orderBean.setAmount(Integer.parseInt(split[2]));
        // 3.合并大小表数据
        orderBean.setProductName(hashMap.get(orderBean.getProductId()));
        // 写出
        context.write(orderBean, NullWritable.get());
    }

    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        System.out.println("maptask结束");
    }
}
3.driver端
package com.zj.practice.mapreduce09.order_map_join;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class order_MapJoin_Driver {
    public static void main(String[] args) throws IOException, URISyntaxException, ClassNotFoundException, InterruptedException {
        Configuration configuration = new Configuration();
        Job job = Job.getInstance(configuration);

        job.setJarByClass(order_MapJoin_Driver.class);
        job.setMapperClass(order_MapJoin_Mapper.class);

        job.setMapOutputKeyClass(order_MapJoin_Bean.class);
        job.setMapOutputValueClass(NullWritable.class);

        // 加载小表文件到缓存
        job.addCacheFile(URI.create("file:///E:/BigData/MapReduce01/src/test/input/mapJoin/pd.txt"));
        //设置reduceTask的数量为0
        job.setNumReduceTasks(0);

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

        boolean res = job.waitForCompletion(true);
        System.exit(res ? 0 : 1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值