MapReduce中多表合并案例

一.案例需求

订单数据表t_order:

id

pid

amount

1001

01

1

1002

02

2

1003

03

3

订单数据order.txt


商品信息表t_product

pid

pname

01

小米

02

华为

03

格力

商品数据pd.txt

    小米
华为
格力

将商品信息表中数据根据商品pid合并到订单数据表中。

最终数据形式:

id

pname

amount

1001

小米

1

1004

小米

4

1002

华为

2

1005

华为

5

1003

格力

3

1006

格力

6

二.reduce端表合并(数据倾斜

通过将关联条件作为map输出的key,将两表满足join条件的数据并携带数据所来源的文件信息,发往同一个reduce task,在reduce中进行数据的串联。

1)创建商品和订合并后的bean类

package com.xyg.mapreduce.table;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable; public class TableBean implements Writable {
private String order_id; // 订单id
private String p_id; // 产品id
private int amount; // 产品数量
private String pname; // 产品名称
private String flag;// 表的标记 public TableBean() {
super();
} public TableBean(String order_id, String p_id, int amount, String pname, String flag) {
super();
this.order_id = order_id;
this.p_id = p_id;
this.amount = amount;
this.pname = pname;
this.flag = flag;
} public String getFlag() {
return flag;
} public void setFlag(String flag) {
this.flag = flag;
} public String getOrder_id() {
return order_id;
} public void setOrder_id(String order_id) {
this.order_id = order_id;
} public String getP_id() {
return p_id;
} public void setP_id(String p_id) {
this.p_id = p_id;
} public int getAmount() {
return amount;
} public void setAmount(int amount) {
this.amount = amount;
} public String getPname() {
return pname;
} public void setPname(String pname) {
this.pname = pname;
} @Override
public void write(DataOutput out) throws IOException {
out.writeUTF(order_id);
out.writeUTF(p_id);
out.writeInt(amount);
out.writeUTF(pname);
out.writeUTF(flag);
} @Override
public void readFields(DataInput in) throws IOException {
this.order_id = in.readUTF();
this.p_id = in.readUTF();
this.amount = in.readInt();
this.pname = in.readUTF();
this.flag = in.readUTF();
} @Override
public String toString() {
return order_id + "\t" + pname + "\t" + amount + "\t" ;
}
}

2)编写TableMapper程序

package com.xyg.mapreduce.table;

import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileSplit; public class TableMapper extends Mapper<LongWritable, Text, Text, TableBean>{
TableBean bean = new TableBean();
Text k = new Text(); @Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException { // 1 获取输入文件类型
FileSplit split = (FileSplit) context.getInputSplit();
String name = split.getPath().getName(); // 2 获取输入数据
String line = value.toString(); // 3 不同文件分别处理
if (name.startsWith("order")) {// 订单表处理
// 3.1 切割
String[] fields = line.split(","); // 3.2 封装bean对象
bean.setOrder_id(fields[]);
bean.setP_id(fields[]);
bean.setAmount(Integer.parseInt(fields[]));
bean.setPname("");
bean.setFlag(""); k.set(fields[]);
}else {// 产品表处理
// 3.3 切割
String[] fields = line.split(","); // 3.4 封装bean对象
bean.setP_id(fields[]);
bean.setPname(fields[]);
bean.setFlag("");
bean.setAmount();
bean.setOrder_id(""); k.set(fields[]);
}
// 4 写出
context.write(k, bean);
}
}

3)编写TableReducer程序

package com.xyg.mapreduce.table;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; public class TableReducer extends Reducer<Text, TableBean, TableBean, NullWritable> { @Override
protected void reduce(Text key, Iterable<TableBean> values, Context context) throws IOException, InterruptedException { // 1准备存储订单的集合
ArrayList<TableBean> orderBeans = new ArrayList<>();
// 2 准备bean对象
TableBean pdBean = new TableBean(); for (TableBean bean : values) { if ("".equals(bean.getFlag())) {// 订单表
// 拷贝传递过来的每条订单数据到集合中
TableBean orderBean = new TableBean();`
try {
BeanUtils.copyProperties(orderBean, bean);
} catch (Exception e) {
e.printStackTrace();
} orderBeans.add(orderBean);
} else {// 产品表
try {
// 拷贝传递过来的产品表到内存中
BeanUtils.copyProperties(pdBean, bean);
} catch (Exception e) {
e.printStackTrace();
}
}
} // 3 表的拼接
for(TableBean bean:orderBeans){
bean.getPname(pdBean.getPname()); // 4 数据写出去
context.write(bean, NullWritable.get());
}
}
}

4)编写TableDriver程序

package com.xyg.mapreduce.table;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class TableDriver { public static void main(String[] args) throws Exception {
// 1 获取配置信息,或者job对象实例
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration); // 2 指定本程序的jar包所在的本地路径
job.setJarByClass(TableDriver.class); // 3 指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(TableMapper.class);
job.setReducerClass(TableReducer.class); // 4 指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(TableBean.class); // 5 指定最终输出的数据的kv类型
job.setOutputKeyClass(TableBean.class);
job.setOutputValueClass(NullWritable.class); // 6 指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[])); // 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行
boolean result = job.waitForCompletion(true);
System.exit(result ? : );
}
}

3)运行程序查看结果

1001    小米    1
1001 小米 1
1002 华为 2
1002 华为 2
1003 格力 3
1003 格力 3

缺点:这种方式中,合并的操作是在reduce阶段完成,reduce端的处理压力太大,map节点的运算负载则很低,资源利用率不高,且在reduce阶段极易产生数据倾斜

解决方案: map端实现数据合并

三.map端表合并(Distributedcache)

1.分析

适用于关联表中有小表的情形;

可以将小表分发到所有的map节点,这样,map节点就可以在本地对自己所读到的大表数据进行合并并输出最终结果,可以大大提高合并操作的并发度,加快处理速度。

2.实操案例

(1)先在驱动模块中添加缓存文件

package test;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class DistributedCacheDriver { public static void main(String[] args) throws Exception {
// 1 获取job信息
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration); // 2 设置加载jar包路径
job.setJarByClass(DistributedCacheDriver.class); // 3 关联map
job.setMapperClass(DistributedCacheMapper.class); // 4 设置最终输出数据类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class); // 5 设置输入输出路径
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[])); // 6 加载缓存数据
job.addCacheFile(new URI("file:///e:/inputcache/pd.txt")); // 7 map端join的逻辑不需要reduce阶段,设置reducetask数量为0
job.setNumReduceTasks(); // 8 提交
boolean result = job.waitForCompletion(true);
System.exit(result ? : );
}
}

(2)读取缓存的文件数据

package test;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
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; public class DistributedCacheMapper extends Mapper<LongWritable, Text, Text, NullWritable>{ Map<String, String> pdMap = new HashMap<>(); @Override
protected void setup(Mapper<LongWritable, Text, Text, NullWritable>.Context context)
throws IOException, InterruptedException {
// 1 获取缓存的文件
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("pd.txt"),"UTF-8")); String line;
while(StringUtils.isNotEmpty(line = reader.readLine())){
// 2 切割
String[] fields = line.split("\t"); // 3 缓存数据到集合
pdMap.put(fields[], fields[]);
} // 4 关流
reader.close();
} Text k = new Text(); @Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 1 获取一行
String line = value.toString(); // 2 截取
String[] fields = line.split("\t"); // 3 获取产品id
String pId = fields[]; // 4 获取商品名称
String pdName = pdMap.get(pId); // 5 拼接
k.set(line + "\t"+ pdName); // 6 写出
context.write(k, NullWritable.get());
}
}

Hadoop案例(七)MapReduce中多表合并的更多相关文章

  1. hadoop学习(七)----mapReduce原理以及操作过程

    前面我们使用HDFS进行了相关的操作,也了解了HDFS的原理和机制,有了分布式文件系统我们如何去处理文件呢,这就的提到hadoop的第二个组成部分-MapReduce. MapReduce充分借鉴了分 ...

  2. Hadoop压缩之MapReduce中使用压缩

    1.压缩和输入分片 Hadoop中文件是以块的形式存储在各个DataNode节点中,假如有一个文件A要做为输入数据,给MapReduce处理,系统要做的,首先从NameNode中找到文件A存储在哪些D ...

  3. Hadoop框架下MapReduce中的map个数如何控制

    控制map个数的核心源码 long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job)); //getFormatMinS ...

  4. MapReduce案例:统计共同好友+订单表多表合并+求每个订单中最贵的商品

    案例三: 统计共同好友 任务需求: 如下的文本, A:B,C,D,F,E,OB:A,C,E,KC:F,A,D,ID:A,E,F,LE:B,C,D,M,LF:A,B,C,D,E,O,MG:A,C,D,E ...

  5. mysql两表合并,对一列数据进行处理

    加班一时爽,一直加班~一直爽~  欢迎收看http://www.996.icu/ 今天弄了下MySQL中两表合并的并且要处理一列数据,这列数据原来都是小写字母,处理时将这列数据改成驼峰命名的~~ 基本 ...

  6. Hadoop学习笔记—12.MapReduce中的常见算法

    一.MapReduce中有哪些常见算法 (1)经典之王:单词计数 这个是MapReduce的经典案例,经典的不能再经典了! (2)数据去重 "数据去重"主要是为了掌握和利用并行化思 ...

  7. 从Hadoop框架与MapReduce模式中谈海量数据处理(含淘宝技术架构) (转)

    转自:http://blog.csdn.net/v_july_v/article/details/6704077 从hadoop框架与MapReduce模式中谈海量数据处理 前言 几周前,当我最初听到 ...

  8. hadoop笔记之MapReduce的应用案例(利用MapReduce进行排序)

    MapReduce的应用案例(利用MapReduce进行排序) MapReduce的应用案例(利用MapReduce进行排序) 思路: Reduce之后直接进行结果合并 具体样例: 程序名:Sort. ...

  9. MapReduce 示例:减少 Hadoop MapReduce 中的侧连接

    摘要:在排序和reducer 阶段,reduce 侧连接过程会产生巨大的网络I/O 流量,在这个阶段,相同键的值被聚集在一起. 本文分享自华为云社区<MapReduce 示例:减少 Hadoop ...

随机推荐

  1. 流媒体协议之JRTPLIB的使用20170919

    主要介绍JRTPLIB 2.x系列和3.x系列两种版本,它们的区别是2.x系列代码量少使用简单,但是只支持RFC 1889不支持RFC 3550,3.x支持RFC 3550,但代码量稍多,以及使用也稍 ...

  2. win7系统用笔记本共享wifi热点 让手机免费上网

    之前一直在用这个方法把自己的笔记本变成一个wifi热点,让手机也可以直接连wifi上网,节省网费和路由器购买费. 其实就是开启了windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP ...

  3. selenium - 查看selenium版本信息

    1. pip list 2. pip show selenium 3. cmd>>python >>> import selenium>>> help( ...

  4. Codeforces 894.D Ralph And His Tour in Binary Country

    D. Ralph And His Tour in Binary Country time limit per test 2.5 seconds memory limit per test 512 me ...

  5. mac下php添加openssl扩展

    进入php源码目录 cd ext/openssl mv config0.m4 config.m4 phpize && ./configure  && make & ...

  6. 9.Android UiAutomator正则表达式的使用

    一.正则表达式元字符: 1.一些常用元字符: 元字符 描述 . 表示任意一个字符 \s 空格字符(空格键.tab.换行.换页.回车) \S 非空字符串([^\s]) \d 一个数字(相当于[0-9]中 ...

  7. Oracle恢复误删除表操作语句

    一.表和数据恢复 1.从回收站里查询被删除的表 select object_name,original_name,partition_name,type,ts_name,createtime,drop ...

  8. Codeforces 807 A Is it rated?

    http://codeforces.com/problemset/problem/807/A A. Is it rated? time limit per test              2 se ...

  9. linux系统df和du命令的区别

    发现一台用户的电脑,df检查出来的/磁盘空间占用了16G,比用du查看得到的磁盘空间大的多,du查看/下所有程序目录加起来还不到5G.这是什么原因呢? 即便是有隐藏文件,查了也很小啊.   因为df和 ...

  10. jQuery()方法的第二个参数详解

    关于jQuery()方法的第二个参数,有下面这几种用法: 1.jQuery(selector, [context]) 这种用法,相当于 $(context).find(selector) 或者 con ...