-
主要介绍用DataJoin类来链接多数据源,先看一下例子,假设二个数据源customs和orders
customer ID Name PhomeNumber
1 赵一 025-5455-566
2 钱二 025-4587-565
3 孙三 021-5845-5875
客户的订单号:
Customer ID order ID Price Data
2 1 93 2008-01-08
3 2 43 2012-01-21
1 3 43 2012-05-12
2 4 32 2012-5-14
问题:现在要生成订单
customer ID name PhomeNumber Price Data
2 钱二 025-4587-565 93 2008-01-08
上面是一个例子,下面介绍一下hadoop中DataJoin类具体的做法。
首先,需要为不同数据源下的每个数据定义一个数据标签,这一点不难理解,就是标记数据的出处。
其次,需要为每个待链接的数据记录确定一个链接主键,这一点不难理解。DataJoin类库分别在map阶段和Reduce阶段提供一个处理框架,尽可能帮助程序员完成一些处理的工作,仅仅留下一些必须工作,由程序完成。
Map阶段
DataJoin类库里有一个抽象基类DataJoinMapperBase,该基类实现了map方法,该方法为对每个数据源下的文本的记录生成一个带表见的数据记录对象。但是程序必须指定它是来自于哪个数据源,即Tag,还要指定它的主键是什么即GroupKey。如果指定了Tag和GroupKey,那么map将会生成一下的记录,customer表为例customers 1 赵一 025-5455-566; customers 2 钱二 025-4587-565;
Map过程中Tag和GroupKey都是程序员给定,所以要肯定要就有接口供程序员去实现,DataJoinMapperBase实现下面3个接口。
abstract Text gernerateInputTag(String inuptFile), 看方法名就知道是设置Tag。
abstract Text generateGroupKey(TaggedMapOutput lineRecord), 该方法是设置GroupKey,其中,lineRecord是数据源中的一行数据,该方法可以在这一行数据上设置任意的GroupKey为主键。
abstract TaggedMapOutput generateMapOutput(object value), 该抽象方法用于把数据源中的原始数据记录包装成一个带标签的数据源。TaggedMapOutputs是一行记录的数据类型。代码如下:
01.
import
org.apache.hadoop.contrib.utils.join.*;
02.
import
org.apache.hadoop.contrib.utils.join.TaggedMapOutput;
03.
import
org.apache.hadoop.io.Text;
04.
05.
public
class
MapClass
extends
DataJoinMapperBase{
06.
07.
@Override
08.
protected
Text generateGroupKey(TaggedMapOutput arg0) {
09.
String line = ((Text)arg0.getData()).toString();
10.
String[] tokens = line.split(
","
);
11.
String groupKey = tokens[
0
];
12.
return
new
Text(groupKey);
13.
}
14.
15.
@Override
16.
protected
Text generateInputTag(String arg0) {
17.
18.
String dataSource = arg0.split(
"-"
)[
0
];
19.
return
new
Text(dataSource);
20.
}
21.
22.
@Override
23.
protected
TaggedMapOutput generateTaggedMapOutput(Object arg0) {
24.
TaggedWritable tw =
new
TaggedWritable((Text)arg0);
25.
tw.setTag(
this
.inputTag);
26.
return
tw;
27.
}
28.
}
01.
import
java.io.DataInput;
02.
import
java.io.DataOutput;
03.
import
java.io.IOException;
04.
import
org.apache.hadoop.contrib.utils.join.TaggedMapOutput;
05.
import
org.apache.hadoop.io.Text;
06.
import
org.apache.hadoop.io.Writable;
07.
08.
public
class
TaggedWritable
extends
TaggedMapOutput{
09.
10.
private
Writable data;
11.
public
TaggedWritable(Writable data) {
12.
this
.tag =
new
Text(
""
);
13.
this
.data = data;
14.
}
15.
16.
@Override
17.
public
Writable getData() {
18.
return
data;
19.
}
20.
21.
@Override
22.
public
void
readFields(DataInput arg0)
throws
IOException {
23.
this
.tag.readFields(arg0);
24.
this
.data.readFields(arg0);
25.
}
26.
27.
@Override
28.
public
void
write(DataOutput arg0)
throws
IOException {
29.
this
.tag.write(arg0);
30.
this
.data.write(arg0);
31.
}
32.
}
每个记录的数据源标签可以由generateInputTag()产生,通过setTag()方法设置记录的Tag。
note:1.该记录不是关系数据库,是文本文件,2. TaggedMapOutput在import org.apache.hadoop.contrib.utils.join.*头文件中,有的时候在eclipse下,每个这个头文件,这时 只要找到你的hadoop的目录下contrib/datajoin文件加,把jar文件导入eclipse中即可。
Reduce 阶段
DataJoinReduceBase中已经实现reduce()方法,具有同一GroupKey的数据分到同一Reduce中,通过reduce的方法将对来自不同的数据源和据用相同的GroupKey做一次叉积组合。这个比较难懂,举个例子:
customers 2 钱二 025-4587-565;
orders 2 1 93 2008-01-08;
orders 2 4 32 2012-5-14
按照map()结果的数据,就是下表给出的结果(3个记录),他们都有一个共同的GroupKey,带来自于二个数据源,所以叉积的结果为
customers 2 钱二 025-4587-565
orders 2 1 93 2008-01-08
customers 2 钱二 025-4587-565orders 2 4 32 2012-5-14
如果Reduce阶段看懂了,基本上这个就搞定了,Reduce是系统做的,不需要用户重载,接下来的工作就是要实现一个combine()函数,它的作用是将每个叉积合并起来,形成订单的格式。
代码如下:
01.
import
org.apache.hadoop.conf.Configuration;
02.
import
org.apache.hadoop.contrib.utils.join.DataJoinReducerBase;
03.
import
org.apache.hadoop.contrib.utils.join.TaggedMapOutput;
04.
import
org.apache.hadoop.fs.Path;
05.
import
org.apache.hadoop.io.Text;
06.
import
org.apache.hadoop.mapred.JobClient;
07.
import
org.apache.hadoop.mapred.JobConf;
08.
import
org.apache.hadoop.mapred.jobcontrol.Job;
09.
import
org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
10.
import
org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
11.
12.
public
class
ReduceClass
extends
DataJoinReducerBase{
13.
14.
@Override
15.
protected
TaggedMapOutput combine(Object[] tags, Object[] values) {
16.
if
(tags.length<
2
)
return
null
;
17.
StringBuffer joinData =
new
StringBuffer();
18.
int
count=
0
;
19.
20.
for
(Object value: values){
21.
joinData.append(
","
);
22.
TaggedWritable tw = (TaggedWritable)value;
23.
String recordLine = ((Text)tw.getData()).toString();
24.
String[] tokens = recordLine.split(
","
,
2
);
25.
if
(count==
0
) joinData.append(tokens[
0
]);
26.
joinData.append(tokens[
1
]);
27.
}
28.
29.
TaggedWritable rtv =
new
TaggedWritable(
new
Text(
new
String(joinData)));
30.
rtv.setTag((Text)tags[
0
]);
31.
return
rtv;
32.
}
33.
34.
public
static
void
main(String[] args){
35.
36.
Configuration conf =
new
Configuration();
37.
JobConf job =
new
JobConf(conf, ReduceClass.
class
);
38.
39.
Path in =
new
Path(args[
0
]);
40.
Path out =
new
Path(args[
1
]);
41.
FileInputFormat.setInputPaths(job, in);
42.
FileOutputFormat.setOutputPath(job, out);
43.
job.setJobName(
"DataJoin"
);
44.
job.setMapperClass(MapClass.
class
);
45.
job.setReducerClass(ReduceClass.
class
);
46.
47.
job.setInputFormat(TextInputFormat.
class
);
48.
job.setOutputFormat(TextOutputFormat.
class
);
49.
job.setOutputKeyClass(Text.
class
);
50.
job.setOutputValueClass(TaggedWritable.
class
);
51.
job.set(
"mapred.textoutputformat.separator"
,
","
);
52.
JobClient.runJob(job);
53.
54.
}
55.
}
MapReduce DataJoin 链接多数据源
最新推荐文章于 2021-08-13 13:04:17 发布