MapReduce之Reduce Join
一 介绍
Reduce Join其主要思想如下:
在map阶段,map函数同时读取两个文件File1和File2,为了区分两种来源的key/value数据对,对每条数据打一个标签(tag), 比如:tag=0表示来自文件File1,tag=2表示来自文件File2。即:map阶段的主要任务是对不同文件中的数据打标签。在reduce阶段,reduce函数获取key相同的来自File1和File2文件的value list, 然后对于同一个key,对File1和File2中的数据进行join(笛卡尔乘积),即:reduce阶段进行实际的连接操作。
在这个例子中我们假设有两个数据文件如下:
存储客户信息的文件:customers.csv
1,stephaie leung,555-555-5555
2,edward kim,123-456-7890
3,jose madriz,281-330-8004
4,david storkk,408-55-0000
存储订单信息的文件:orders.csv
3,A,12.95,02-Jun-2008
1,B,88.25,20-May-2008
2,C,32.00,30-Nov-2007
3,D,25.02,22-Jan-2009
要求最终的输出结果为:
1,Stephanie Leung,555-555-5555,B,88.25,20-May-2008
2,Edward Kim,123-456-7890,C,32.00,30-Nov-2007
3,Jose Madriz,281-330-8004,A,12.95,02-Jun-2008
3,Jose Madriz,281-330-8004,D,25.02,22-Jan-2009
二 代码部分
自定义数据类型:用于对不同文件数据打标签
package mapreduce.reducejoin; import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable; public class DataJoinWritable implements Writable { // mark ,customer / order
private String tag; // info
private String data; public DataJoinWritable() { } public DataJoinWritable(String tag, String data) {
this.set(tag, data);
} public void set(String tag, String data) {
this.setTag(tag);
this.setData(data);
} public String getTag() {
return tag;
} public void setTag(String tag) {
this.tag = tag;
} public String getData() {
return data;
} public void setData(String data) {
this.data = data;
} public void write(DataOutput out) throws IOException {
out.writeUTF(this.getTag());
out.writeUTF(this.getData());
} public void readFields(DataInput in) throws IOException {
this.setTag(in.readUTF());
this.setData(in.readUTF());
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DataJoinWritable other = (DataJoinWritable) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
if (tag == null) {
if (other.tag != null)
return false;
} else if (!tag.equals(other.tag))
return false;
return true;
} @Override
public String toString() {
return tag + "," + data;
}
}
MapReduce代码部分
package mapreduce.reducejoin; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; public class DataJoinMapReduce extends Configured implements Tool { // step 1: Mapper
public static class DataJoinMapper extends
Mapper<LongWritable, Text, LongWritable, DataJoinWritable> { // map output key
private LongWritable mapOutputKey = new LongWritable(); // map output value
private DataJoinWritable mapOutputValue = new DataJoinWritable(); @Override
public void setup(Context context) throws IOException,
InterruptedException {
} @Override
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException { // line value
String lineValue = value.toString(); // split
String[] vals = lineValue.split(","); int length = vals.length; if ((3 != length) && (4 != length)) {
return;
} // get cid
Long cid = Long.valueOf(vals[0]); // get name
String name = vals[1]; // set customer
if (3 == length) {
String phone = vals[2]; // set
mapOutputKey.set(cid);
mapOutputValue.set("customer", name + "," + phone);
} // set order
if (4 == length) {
String price = vals[2];
String date = vals[3]; // set
mapOutputKey.set(cid);
mapOutputValue.set("order", name + "," + price + "," + date);
} // output
context.write(mapOutputKey, mapOutputValue); } @Override
public void cleanup(Context context) throws IOException,
InterruptedException {
}
} // step 2: Reducer
public static class DataJoinReducer extends
Reducer<LongWritable, DataJoinWritable, NullWritable, Text> { private Text outputValue = new Text(); @Override
protected void setup(Context context) throws IOException,
InterruptedException {
} @Override
protected void reduce(LongWritable key,
Iterable<DataJoinWritable> values, Context context)
throws IOException, InterruptedException {
String customerInfo = null;
List<String> orderList = new ArrayList<String>(); for (DataJoinWritable value : values) {
if ("customer".equals(value.getTag())) {
customerInfo = value.getData();
} else if ("order".equals(value.getTag())) {
orderList.add(value.getData());
}
} // output
for (String order : orderList) { // ser outout value
outputValue.set(key.get() + "," + customerInfo + "," + order); // output
context.write(NullWritable.get(), outputValue);
}
} @Override
protected void cleanup(Context context) throws IOException,
InterruptedException {
}
} /**
* Execute the command with the given arguments.
*
* @param args
* command specific arguments.
* @return exit code.
* @throws Exception
*/ // step 3: Driver
public int run(String[] args) throws Exception { Configuration configuration = this.getConf(); // set job
Job job = Job.getInstance(configuration, this.getClass().getSimpleName());
job.setJarByClass(DataJoinMapReduce.class); // input
Path inpath = new Path(args[0]);
FileInputFormat.addInputPath(job, inpath); // output
Path outPath = new Path(args[1]);
FileOutputFormat.setOutputPath(job, outPath); // Mapper
job.setMapperClass(DataJoinMapper.class);
job.setMapOutputKeyClass(LongWritable.class);
job.setMapOutputValueClass(DataJoinWritable.class); // Reducer
job.setReducerClass(DataJoinReducer.class);
job.setOutputKeyClass(NullWritable.class);
job.setOutputValueClass(Text.class); // submit job -> YARN
boolean isSuccess = job.waitForCompletion(true);
return isSuccess ? 0 : 1; } public static void main(String[] args) throws Exception { Configuration configuration = new Configuration(); args = new String[] {
"hdfs://beifeng01:8020/user/beifeng01/mapreduce/input/reducejoin",
"hdfs://beifeng01:8020/user/beifeng01/mapreduce/output" }; // run job
int status = ToolRunner.run(configuration, new DataJoinMapReduce(),
args); // exit program
System.exit(status);
}
}
执行代码后查询结果
[hadoop@beifeng01 hadoop-2.5.0-cdh5.3.6]$ bin/hdfs dfs -text /user/beifeng01/mapreduce/output/p*
1,stephaie leung,555-555-5555,B,88.25,20-May-2008
2,edward kim,123-456-7890,C,32.00,30-Nov-2007
3,jose madriz,281-330-8004,D,25.02,22-Jan-2009
3,jose madriz,281-330-8004,A,12.95,02-Jun-2008
MapReduce之Reduce Join的更多相关文章
- Hadoop学习之路(二十一)MapReduce实现Reduce Join(多个文件联合查询)
MapReduce Join 对两份数据data1和data2进行关键词连接是一个很通用的问题,如果数据量比较小,可以在内存中完成连接. 如果数据量比较大,在内存进行连接操会发生OOM.mapredu ...
- MapReduce编程之Reduce Join多种应用场景与使用
在关系型数据库中 Join 是非常常见的操作,各种优化手段已经到了极致.在海量数据的环境下,不可避免的也会碰到这种类型的需求, 例如在数据分析时需要连接从不同的数据源中获取到数据.不同于传统的单机模式 ...
- MapReduce的Reduce side Join
1. 简单介绍 reduce side join是全部join中用时最长的一种join,可是这样的方法可以适用内连接.left外连接.right外连接.full外连接和反连接等全部的join方式.r ...
- MapReduce实现的Join
MapReduce Join 对两份数据data1和data2进行关键词连接是一个很通用的问题,如果数据量比较小,可以在内存中完成连接. 如果数据量比较大,在内存进行连接操会发生OOM.mapredu ...
- MapReduce三种join实例分析
本文引自吴超博客 实现原理 1.在Reudce端进行连接. 在Reudce端进行连接是MapReduce框架进行表之间join操作最为常见的模式,其具体的实现原理如下: Map端的主要工作:为来自不同 ...
- MapReduce中的Join
一. MR中的join的两种方式: 1.reduce side join(面试题) reduce side join是一种最简单的join方式,其主要思想如下: 在map阶段,map函数同时读取两个文 ...
- MapReduce之Map Join
一 介绍 之所以存在Reduce Join,是因为在map阶段不能获取所有需要的join字段,即:同一个key对应的字段可能位于不同map中.Reduce side join是非常低效的,因为shuf ...
- Mapreduce中的join操作
一.背景 MapReduce提供了表连接操作其中包括Map端join.Reduce端join还有半连接,现在我们要讨论的是Map端join,Map端join是指数据到达map处理函数之前进行合并的,效 ...
- mapreduce作业reduce被大量kill掉
之前有一段时间.我们的hadoop2.4集群压力非常大.导致提交的job出现大量的reduce被kill掉.同样的job执行时间比在hadoop0.20.203上面长了非常多.这个问题事实上是redu ...
随机推荐
- css属性值语法解读
//margin 形式语法: [ <length> | <percentage> | auto ]{1,4} //合法实例: margin: style /*单值语法 */ 举 ...
- 使用UIDynamicAnimator创建重力感应的View
使用UIDynamicAnimator创建重力感应的View http://www.raywenderlich.com/zh-hans/52617/uikit-力学教程 详细教程请参考上面的链接,此处 ...
- Hyper-V迁移---委派
在Hyper-V管理器中-实时迁移,选择“使用kerberos",如图1所示 在AD中,找到Hyper-V宿主,分别设置委派,如图2所示 图1 图2
- 上传附件(图片base64)封装方法
上传附件(图片base64)封装方法 php 上传附件,base64 项目中封装的接口: public function error($msg){ header("Content-type: ...
- PhoneGap 的文件 api
一. 文件系统的请求 请求文件系统通过 window.requestFileSystem 来完函数声明如下: window.requestFileSystem(type, size, successC ...
- bzoj3718 [PA2014]Parking
Description 你的老板命令你将停车场里的车移动成他想要的样子.停车场是一个长条矩形,宽度为w.我们以其左下角顶点为原点,坐标轴平行于矩形的边,建立直角坐标系.停车场很长,我们可以认为它一直向 ...
- luogu P4275 萃香的请柬
嘟嘟嘟 打表不难发现,序列的长度以及序列中1的个数都是斐波那契数列.因为第 i 秒1的个数由 i - 1的1和 i - 2的0变换而来,那么f[i] = f[i - 1] + f[i - 2].序列的 ...
- 4springboot:日志(上)
1.主流的日志框架 2.SLF4J使用 如何在系统中使用SLF4j https://www.slf4j.org 以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面 ...
- 2.spring:集合属性
1.list 配置java.util.List类型的属性,需要指定<list>标签,在标签里面包含有一些元素,这些标签 可以通过<value>指定简单的常量值,通过<r ...
- 关于使用eclipse maven UpdateProject时报错,无法更新本地仓库的问题解决方案
在做项目中,需要从同事电脑中把Maven项目copy过来,但是copy的过程中只copy了代码,setting.xml文件和pom.xml,使用eclipse把项目导入,有红色的感叹号提示,由于我没有 ...