MapReduce中多表合并案例

一.案例需求

订单数据表t_order:

id

pid

amount

1001

01

1

1002

02

2

1003

03

3

订单数据order.txt

  1.  

商品信息表t_product

pid

pname

01

小米

02

华为

03

格力

商品数据pd.txt

  1. 小米
  2. 华为
  3. 格力

将商品信息表中数据根据商品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类

  1. package com.xyg.mapreduce.table;
  2.  
  3. import java.io.DataInput;
  4. import java.io.DataOutput;
  5. import java.io.IOException;
  6. import org.apache.hadoop.io.Writable;
  7.  
  8. public class TableBean implements Writable {
  9. private String order_id; // 订单id
  10. private String p_id; // 产品id
  11. private int amount; // 产品数量
  12. private String pname; // 产品名称
  13. private String flag;// 表的标记
  14.  
  15. public TableBean() {
  16. super();
  17. }
  18.  
  19. public TableBean(String order_id, String p_id, int amount, String pname, String flag) {
  20. super();
  21. this.order_id = order_id;
  22. this.p_id = p_id;
  23. this.amount = amount;
  24. this.pname = pname;
  25. this.flag = flag;
  26. }
  27.  
  28. public String getFlag() {
  29. return flag;
  30. }
  31.  
  32. public void setFlag(String flag) {
  33. this.flag = flag;
  34. }
  35.  
  36. public String getOrder_id() {
  37. return order_id;
  38. }
  39.  
  40. public void setOrder_id(String order_id) {
  41. this.order_id = order_id;
  42. }
  43.  
  44. public String getP_id() {
  45. return p_id;
  46. }
  47.  
  48. public void setP_id(String p_id) {
  49. this.p_id = p_id;
  50. }
  51.  
  52. public int getAmount() {
  53. return amount;
  54. }
  55.  
  56. public void setAmount(int amount) {
  57. this.amount = amount;
  58. }
  59.  
  60. public String getPname() {
  61. return pname;
  62. }
  63.  
  64. public void setPname(String pname) {
  65. this.pname = pname;
  66. }
  67.  
  68. @Override
  69. public void write(DataOutput out) throws IOException {
  70. out.writeUTF(order_id);
  71. out.writeUTF(p_id);
  72. out.writeInt(amount);
  73. out.writeUTF(pname);
  74. out.writeUTF(flag);
  75. }
  76.  
  77. @Override
  78. public void readFields(DataInput in) throws IOException {
  79. this.order_id = in.readUTF();
  80. this.p_id = in.readUTF();
  81. this.amount = in.readInt();
  82. this.pname = in.readUTF();
  83. this.flag = in.readUTF();
  84. }
  85.  
  86. @Override
  87. public String toString() {
  88. return order_id + "\t" + pname + "\t" + amount + "\t" ;
  89. }
  90. }

2)编写TableMapper程序

  1. package com.xyg.mapreduce.table;
  2.  
  3. import java.io.IOException;
  4. import org.apache.hadoop.io.LongWritable;
  5. import org.apache.hadoop.io.Text;
  6. import org.apache.hadoop.mapreduce.Mapper;
  7. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  8.  
  9. public class TableMapper extends Mapper<LongWritable, Text, Text, TableBean>{
  10. TableBean bean = new TableBean();
  11. Text k = new Text();
  12.  
  13. @Override
  14. protected void map(LongWritable key, Text value, Context context)
  15. throws IOException, InterruptedException {
  16.  
  17. // 1 获取输入文件类型
  18. FileSplit split = (FileSplit) context.getInputSplit();
  19. String name = split.getPath().getName();
  20.  
  21. // 2 获取输入数据
  22. String line = value.toString();
  23.  
  24. // 3 不同文件分别处理
  25. if (name.startsWith("order")) {// 订单表处理
  26. // 3.1 切割
  27. String[] fields = line.split(",");
  28.  
  29. // 3.2 封装bean对象
  30. bean.setOrder_id(fields[]);
  31. bean.setP_id(fields[]);
  32. bean.setAmount(Integer.parseInt(fields[]));
  33. bean.setPname("");
  34. bean.setFlag("");
  35.  
  36. k.set(fields[]);
  37. }else {// 产品表处理
  38. // 3.3 切割
  39. String[] fields = line.split(",");
  40.  
  41. // 3.4 封装bean对象
  42. bean.setP_id(fields[]);
  43. bean.setPname(fields[]);
  44. bean.setFlag("");
  45. bean.setAmount();
  46. bean.setOrder_id("");
  47.  
  48. k.set(fields[]);
  49. }
  50. // 4 写出
  51. context.write(k, bean);
  52. }
  53. }

3)编写TableReducer程序

  1. package com.xyg.mapreduce.table;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import org.apache.commons.beanutils.BeanUtils;
  5. import org.apache.hadoop.io.NullWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapreduce.Reducer;
  8.  
  9. public class TableReducer extends Reducer<Text, TableBean, TableBean, NullWritable> {
  10.  
  11. @Override
  12. protected void reduce(Text key, Iterable<TableBean> values, Context context) throws IOException, InterruptedException {
  13.  
  14. // 1准备存储订单的集合
  15. ArrayList<TableBean> orderBeans = new ArrayList<>();
  16. // 2 准备bean对象
  17. TableBean pdBean = new TableBean();
  18.  
  19. for (TableBean bean : values) {
  20.  
  21. if ("".equals(bean.getFlag())) {// 订单表
  22. // 拷贝传递过来的每条订单数据到集合中
  23. TableBean orderBean = new TableBean();`
  24. try {
  25. BeanUtils.copyProperties(orderBean, bean);
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29.  
  30. orderBeans.add(orderBean);
  31. } else {// 产品表
  32. try {
  33. // 拷贝传递过来的产品表到内存中
  34. BeanUtils.copyProperties(pdBean, bean);
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. }
  40.  
  41. // 3 表的拼接
  42. for(TableBean bean:orderBeans){
  43. bean.getPname(pdBean.getPname());
  44.  
  45. // 4 数据写出去
  46. context.write(bean, NullWritable.get());
  47. }
  48. }
  49. }

4)编写TableDriver程序

  1. package com.xyg.mapreduce.table;
  2.  
  3. import org.apache.hadoop.conf.Configuration;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.NullWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapreduce.Job;
  8. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  10.  
  11. public class TableDriver {
  12.  
  13. public static void main(String[] args) throws Exception {
  14. // 1 获取配置信息,或者job对象实例
  15. Configuration configuration = new Configuration();
  16. Job job = Job.getInstance(configuration);
  17.  
  18. // 2 指定本程序的jar包所在的本地路径
  19. job.setJarByClass(TableDriver.class);
  20.  
  21. // 3 指定本业务job要使用的mapper/Reducer业务类
  22. job.setMapperClass(TableMapper.class);
  23. job.setReducerClass(TableReducer.class);
  24.  
  25. // 4 指定mapper输出数据的kv类型
  26. job.setMapOutputKeyClass(Text.class);
  27. job.setMapOutputValueClass(TableBean.class);
  28.  
  29. // 5 指定最终输出的数据的kv类型
  30. job.setOutputKeyClass(TableBean.class);
  31. job.setOutputValueClass(NullWritable.class);
  32.  
  33. // 6 指定job的输入原始文件所在目录
  34. FileInputFormat.setInputPaths(job, new Path(args[]));
  35. FileOutputFormat.setOutputPath(job, new Path(args[]));
  36.  
  37. // 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行
  38. boolean result = job.waitForCompletion(true);
  39. System.exit(result ? : );
  40. }
  41. }

3)运行程序查看结果

  1. 1001 小米 1
  2. 1001 小米 1
  3. 1002 华为 2
  4. 1002 华为 2
  5. 1003 格力 3
  6. 1003 格力 3

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

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

三.map端表合并(Distributedcache)

1.分析

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

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

2.实操案例

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

  1. package test;
  2. import java.net.URI;
  3. import org.apache.hadoop.conf.Configuration;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.NullWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapreduce.Job;
  8. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  10.  
  11. public class DistributedCacheDriver {
  12.  
  13. public static void main(String[] args) throws Exception {
  14. // 1 获取job信息
  15. Configuration configuration = new Configuration();
  16. Job job = Job.getInstance(configuration);
  17.  
  18. // 2 设置加载jar包路径
  19. job.setJarByClass(DistributedCacheDriver.class);
  20.  
  21. // 3 关联map
  22. job.setMapperClass(DistributedCacheMapper.class);
  23.  
  24. // 4 设置最终输出数据类型
  25. job.setOutputKeyClass(Text.class);
  26. job.setOutputValueClass(NullWritable.class);
  27.  
  28. // 5 设置输入输出路径
  29. FileInputFormat.setInputPaths(job, new Path(args[]));
  30. FileOutputFormat.setOutputPath(job, new Path(args[]));
  31.  
  32. // 6 加载缓存数据
  33. job.addCacheFile(new URI("file:///e:/inputcache/pd.txt"));
  34.  
  35. // 7 map端join的逻辑不需要reduce阶段,设置reducetask数量为0
  36. job.setNumReduceTasks();
  37.  
  38. // 8 提交
  39. boolean result = job.waitForCompletion(true);
  40. System.exit(result ? : );
  41. }
  42. }

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

  1. package test;
  2. import java.io.BufferedReader;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. import org.apache.commons.lang.StringUtils;
  9. import org.apache.hadoop.io.LongWritable;
  10. import org.apache.hadoop.io.NullWritable;
  11. import org.apache.hadoop.io.Text;
  12. import org.apache.hadoop.mapreduce.Mapper;
  13.  
  14. public class DistributedCacheMapper extends Mapper<LongWritable, Text, Text, NullWritable>{
  15.  
  16. Map<String, String> pdMap = new HashMap<>();
  17.  
  18. @Override
  19. protected void setup(Mapper<LongWritable, Text, Text, NullWritable>.Context context)
  20. throws IOException, InterruptedException {
  21. // 1 获取缓存的文件
  22. BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("pd.txt"),"UTF-8"));
  23.  
  24. String line;
  25. while(StringUtils.isNotEmpty(line = reader.readLine())){
  26. // 2 切割
  27. String[] fields = line.split("\t");
  28.  
  29. // 3 缓存数据到集合
  30. pdMap.put(fields[], fields[]);
  31. }
  32.  
  33. // 4 关流
  34. reader.close();
  35. }
  36.  
  37. Text k = new Text();
  38.  
  39. @Override
  40. protected void map(LongWritable key, Text value, Context context)
  41. throws IOException, InterruptedException {
  42. // 1 获取一行
  43. String line = value.toString();
  44.  
  45. // 2 截取
  46. String[] fields = line.split("\t");
  47.  
  48. // 3 获取产品id
  49. String pId = fields[];
  50.  
  51. // 4 获取商品名称
  52. String pdName = pdMap.get(pId);
  53.  
  54. // 5 拼接
  55. k.set(line + "\t"+ pdName);
  56.  
  57. // 6 写出
  58. context.write(k, NullWritable.get());
  59. }
  60. }

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. 【CF962E】Byteland, Berland and Disputed Cities

    Portal! ---> 几句话题意 数轴上面有三种点(B点,R点,P点),现在要将其中的某些点连起来,满足将所有B点去掉之后,所有P点和R点都连通&将所有R点去掉之后,所有B点和P点都 ...

  2. DevExpress Components16.2.6 Source Code 重编译教程

    DevExpress 是一个比较有名的界面控件套件,提供了一系列优秀的界面控件.这篇文章将展示如何在拥有源代码的情况下,对 DevExpress 的程序集进行重新编译. 特别提示:重编译后,已安装好的 ...

  3. 图像灰度化方法总结及其VC实现

    http://blog.csdn.net/likezhaobin/article/details/6915754 最近一段时间作者开始进行运动目标识别定位系统设计,本文以及后续的几篇文章都是从一个图像 ...

  4. jvm容器的关系

    jvm实例,tomcat容器,spring容器,在内存中的关系5 1.一个java项目对应一个jvm 吗? 2.tomcat里面加载多个java项目 ,是不是用了一个jvm? 3.java项目中的sp ...

  5. STL源码分析-bitset

    http://note.youdao.com/noteshare?id=0ea12c1fffd3866c6eddb8dc208c109d

  6. linux 隐藏权限

    原文 ------通过chattr设置档案的隐藏权限------ [root@sdc ~]#chattr --helpUsage: chattr [-RV] [-+=AacDdijsSu] [-v v ...

  7. windows如何要查看IIS连接数

    1.运行,输入,perfmon.msc 2.在系统监视器,区域点击,添加计数器. 3.在“添加计数器”窗口,“性能对象”选择Web Service,“从列表选择计数器”选中Current Connec ...

  8. C11构造函数的改善

    1.委托构造函数 委托构造函数就是允许在同一个类中一个构造函数可以调用另一个构造函数,从而在初始化时简化变量的初始化. class CTest { public: int x; int y; int ...

  9. Dubbo+Zookeeper+SpringMVC+Maven整合实现微服务项目

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  10. Java 里快如闪电的线程间通讯

    这个故事源自一个很简单的想法:创建一个对开发人员友好的.简单轻量的线程间通讯框架,完全不用锁.同步器.信号量.等待和通知,在Java里开发一个轻量.无锁的线程内通讯框架:并且也没有队列.消息.事件或任 ...