Hadoop MapReduce例子-新版API多表连接Join之模仿订单配货
文章为作者原创,未经许可,禁止转载。 -Sun Yat-sen University 冯兴伟
一、 项目简介:
电子商务的发展以及电商平台的多样化,类似于京东和天猫这种拥有过亿用户的在线购物网站,每天要处理的订单数堪称海量,更别提最近的双十一购物节,如此海量的订单数据阿里巴巴和京东是如何准确将用户信息和其订单匹配并配货的呢?答案是数据连接匹配。我的云计算项目idea也是来源于此。我们在做数据分析时常要连接从不同的数据源中获取到的数据,单机模式下的关系型数据库中我们会遇到这问题,同样在分布式系统中也不可避免的会有这种需求。故此,此次项目是用新的API实现在hadoop集群的MapReduce框架中编写程序实现数据的Join操作并模仿双十一订单配货来举例说明。
二、 MapReduce框架简析
MapReduce作为Hadoop的一个计算框架模型,在运行计算任务时,任务被大致分为读取数据分块,Map操作,Shuffle操作,Reduce操作,然后输出结果。

三、 项目预期说明及特色、创新
a. MapReduce输入(user文件和order文件)
存储有大量用户个人信息(用户ID,姓名,电话)的User文件,以下为部分数据示例:
|
U_ID Name Phone 14365 Lembr 287-797-6381 15347 Bawa 454-638-9400 16807 Yazdi 660-341-5047 19368 Wiela 759-382-4590 22591 DAgost 746-786-2796 25946 Liley 772-262-2520 |
存储有大量用户订单数据(用户ID,商品,价格,订单号,下单时间,送货地址)的Order文件,以下为部分数据示例:
|
U_ID Goods Prices Order_ID Time of Order Reserv Address 14365 blanket 98.36 370721695 11-Nov-2016 09:25:19 Garvey 8th Ave 15347 cushion 65.84 482597673 11-Nov-2016 20:20:06 Nogales 1st St 16807 quilt 11.58 408570985 11-Nov-2016 23:41:48 Castleton St 19368 cotton 24.00 342658162 11-Nov-2016 05:30:10 Gale 12rd Ave 22591 bedding 71.72 228726593 11-Nov-2016 13:12:29 Azusa Ave 25946 pillow 24.17 151469234 11-Nov-2016 15:13:45 Artesia Blvd |
b. MapReduce预期输出:

c. 从项目的预期输入我们看到,user和order分别来源于不同的数据源,我们要模仿订单配货的关键就是准确的匹配对应的用户的订单。User文件中只给了我们用户信息,而Order文件中给我们的只有用户在购买商品时登录用的用户ID以及订单的信息。虽然在上面的输入输出数据一一对应也很整齐,但是在实际输入数据文件中是很凌乱的,大量的数据靠肉眼是看不出来的,而我们仔细观察也只发现两个文件中唯一有联系的只有用户ID。这也是我们要做的根据不同文件的仅有的一个共同属性来进行数据连接操作。此项目的特色创新之处就在于用新的API实现了MapReduce框架下的海量数据连接Join操作,以及良好的应用到实际的在线购物订单配货例子中。
四、 程序设计描述
1. 程序的完整代码:
import java.io.IOException;
import java.util.*;
import java.io.DataInput;
import java.io.DataOutput;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class DJoin
{
private static int first = 0;
public static class Map extends Mapper<LongWritable, Text, Text, Text>
{
private Text key = new Text();
private Text value = new Text();
private String[] keyValue = null; protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException
{
String line = value.toString();
if(line.contains("U_ID") == true)
{
return ;
} keyValue = line.split("\t",2);
this.key.set(keyValue[0]);
this.value.set(keyValue[1]);
context.write(this.key, this.value);
}
}
public static class Reduce extends Reducer<Text, Text, Text, Text>
{ private Text value = new Text();
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException
{
if(first == 0)
{
context.write(new Text("User_ID Name Phone Goods Prices Order_ID Time of Order Reserv Address "),null);
first++;
}
String valueStr ="";
String[] save = new String[2];
int i=0;
int j=2;
Iterator its =values.iterator();
while(j>0)
{
save[i++] = its.next().toString();
j--;
}
String one = save[0];
String two = save[1]; char flag = one.charAt(0);
if(flag>='a'&&flag<='z')
{
valueStr += "\t";
valueStr += two;
valueStr += "\t";
valueStr += one;
valueStr += "\t";
}
else
{
valueStr += "\t";
valueStr += one;
valueStr += "\t";
valueStr += two;
valueStr += "\t";
}
this.value.set(valueStr);
context.write(key, this.value);
} } public static void main(String[] args) throws Exception
{
Configuration conf = new Configuration();
args = new GenericOptionsParser(conf, args).getRemainingArgs();
if (args.length != 2) {
System.err.println("Usage: Djoin <input> <output>");
System.exit(2);
}
Job job = new Job(conf, "DJoin");
job.setJarByClass(DJoin.class);
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
2. 下面开始对主体代码进行解释
a) 实现map函数:
map函数首先进行的是行读取,如果是首行则跳过,之后用split分割行,将map操作输出的key值设为两表都有的用户ID,其他字段存储到value中输出。
|
public static class Map extends Mapper<LongWritable, Text, Text, Text>{ private Text key = new Text(); private Text value = new Text(); private String[] keyValue = null; protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{ String line = value.toString(); if(line.contains("U_ID") == true) { return ; } keyValue = line.split("\t",2); this.key.set(keyValue[0]); this.value.set(keyValue[1]); context.write(this.key, this.value); } } |
b) 实现reduce函数:
reduce函数的输入也是key/value的形式,且其value是以迭代器形式,可以简单理解为一个key对应一组的value值。first是全局变量,用来输出表头的各项属性名。对map产生的每一组输出,map产生的key值直接输出到reduce的key值,而map产生的value进行迭代判断其数据来源是User表还是Order表之后进行连接Join操作。
|
public static class Reduce extends Reducer<Text, Text, Text, Text>{ private Text value = new Text(); protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { if(first == 0) { context.write(new Text("User_ID Name Phone Goods Prices Order_ID Time of Order Reserv Address "),null); first++; } String valueStr =""; String[] save = new String[2]; int i=0; int j=2; Iterator its =values.iterator(); while(j>0) { save[i++] = its.next().toString(); j--; } String one = save[0]; String two = save[1]; char flag = one.charAt(0); if(flag>='a'&&flag<='z') { valueStr += "\t"; valueStr += two; valueStr += "\t"; valueStr += one; valueStr += "\t"; } else { valueStr += "\t"; valueStr += one; valueStr += "\t"; valueStr += two; valueStr += "\t"; } this.value.set(valueStr); context.write(key, this.value); } } |
c) 实现main函数:
常规的新建job以及configuration的设置。
|
public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); args = new GenericOptionsParser(conf, args).getRemainingArgs(); if (args.length != 2) { System.err.println("Usage: Djoin <input> <output>"); System.exit(2); } Job = new Job(conf, "DJoin"); job.setJarByClass(DJoin.class); job.setMapperClass(Map.class); job.setReducerClass(Reduce.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); job.setInputFormatClass(TextInputFormat.class); job.setOutputFormatClass(TextOutputFormat.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } |
五、 程序编译及运行:
1) 检查jps,master的jps正常:

status检查正常:

2) 从本机上传文件到品高云平台的虚拟机master上:

3) 编译DJoin.java


4) 打包成DJoin.jar

5) 在hdfs中创建/input/文件夹目录,放入输入文件:

6) 运行DJoin任务:

7) 查看程序输出:

Hadoop MapReduce例子-新版API多表连接Join之模仿订单配货的更多相关文章
- hadoop —— MapReduce例子 (数据去重)
参考:http://eric-gcm.iteye.com/blog/1807468 例子1: 概要:数据去重 描述:将file1.txt.file2.txt中的数据合并到一个文件中的同时去掉重复的内容 ...
- hadoop —— MapReduce例子 (求平均值)
参考:http://eric-gcm.iteye.com/blog/1807468 math.txt: 张三 88 李四 99 王五 66 赵六 77 china.txt: 张三 78 李四 89 王 ...
- hadoop —— MapReduce例子 (数据排序)
参考:http://eric-gcm.iteye.com/blog/1807468 file1.txt: 2 32 654 32 15 756 65223 file2.txt: 5956 22 650 ...
- 表连接join on
表A记录如下: aID aNum 1 a20050111 2 a20050112 3 a20050113 4 a20050114 5 a20050115 表B记录如下: bID bNa ...
- 性能调优7:多表连接 - join
在产品环境中,往往存在着大量的表连接情景,不管是inner join.outer join.cross join和full join(逻辑连接符号),在内部都会转化为物理连接(Physical Joi ...
- sql优化 表连接join方式
sql优化核心 是数据库中 解析器+优化器的工作,我觉得主要有以下几个大方面:1>扫表的方法(索引非索引.主键非主键.书签查.索引下推)2>关联表的方法(三种),关键是内存如何利用 ...
- sql表连接 —— join
一.内连接 —— INNER JOIN 内连接是最常见的一种连接,只连接匹配的行. 表1: 表2: 执行查询: select StudentId as 学生编号,StudentName as 姓名,G ...
- sql 表连接 join
inner join 和 join 的 区别 inner join 是内连接 ,查询出两边 都有的数据 join 是交叉 连接, 假设集合A={a, b},集合B={0, 1, 2},则两个集 ...
- SQL——表连接JOIN
JOIN - 用于根据两个或多个表中的列之间的关系,从这些表中查询数据. 语法:SELECT columnName(s) FROM tableName1 JOIN tableName2 -- 查 ...
随机推荐
- sqlserver 分区表
我们知道很多事情都存在一个分治的思想,同样的道理我们也可以用到数据表上,当一个表很大很大的时候,我们就会想到将表拆 分成很多小表,查询的时候就到各个小表去查,最后进行汇总返回给调用方来加速我们的查询速 ...
- Andorid开发学习---ubuntu 12.04下搭建超好用的安卓模拟器genymotion 安装卸载virtualbox 4.3
什么是Genymotion? Genymotion是一套完整的工具,它提供了Android虚拟环境.它简直就是开发者.测试人员.推销者甚至是游戏玩家的福音. Genymotion支持Windows.L ...
- 多重背包问题:POJ2392
这是一道完全背包问题,只不过增加了限制条件. 在更新最大值的时候,我注释掉了错误的方式,却不明白为什么是错误的,如果有人看到这篇博客,并且知道为什么那样更新是错误的,请指教,谢谢. 上代码: #inc ...
- 使用 IntraWeb (45) - 活用 IntraWeb
asp.net 刚开始时, 也是拖拉控件, 但后来有了 MVC.xNext. 换个思路使用 IntraWeb 吧: 界面全部用 html+js+css 实现(有些会是用 Delphi 动态生成), 然 ...
- Dedecms 首页调用副栏目内容方法
最近一段时间一直打算修改英国移民网的首页,对首页的栏目内容也打算进行一系列的调用设置,可是在调用的时候出现了一些问题:调用不了英国移民网下的“移民快讯”这一副栏目下的内容!于是只能上网求助,在广大的网 ...
- iOS模拟各种网络状态
在iOS开发中我们有在各种不同网络状态下测试app运行状态的需求.苹果给我们提供了在模拟器和真机状态下,模拟各种网络状态的软件. 在模拟器中 苹果提供的模拟网络状态的工具官网地址下载该工具需要登录Ap ...
- 委托 在其他类中修改form中的控件属性
通常情况下,我们需要在其他业务类中将提示信息时时显示到主界面上,可以通过以下方式 Form1.cs using System; ; i < ; i++) { cb ...
- web.xml相关知识摘录整理
web.xml 中的listener. filter.servlet 加载顺序及其详解 在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人 ...
- 【转】Linux下查看文件和文件夹大小
当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择. df可以查看一级文件夹大小.使用比例.档案系统及其挂入点,但对文件却无能为力. du可以查看文件及文件夹的大小. ...
- c# 抓取Web网页数据分析
通过程序自动的读取其它网站网页显示的信息,类似于爬虫程序.比方说我们有一个系统,要提取BaiDu网站上歌曲搜索排名.分析系统在根据得到的数据进行数据分析.为业务提供参考数据. 为了完成以上的需求,我们 ...