Mapreduce连接
1、reduce side join
在reduce端进行表的连接,该方法的特点就是操作简单,缺点是map端shffule后传递给reduce端的数据量过大,极大的降低了性能
连接方法:
(1)map端读入输入数据,以连接键为Key,待连接的内容为value,但是value需要添加特别的标识,表示的内容为表的表示,即若value来自于表1,则标识位设置为1,若来自表2,则设置为2,然后将map的内容输出到reduce
(2)reduce端接收来自map端shuffle后的结果,即<key, values>
内容,然后遍历values,对每一个value进行处理,主要的处理过程是:判断每一个标志位,如果来自1表,则将value放置在特地为1表创建的数组之中,若来自2表,则将value放置在为2表创建的数组中,最后对两个数组进行求笛卡儿积,然后输出结果,即为最终表的连接结果。
2、map side join
在map端进行表的连接,对表的大小有要求,首先有一个表必须足够小,可以读入内存,另外的一个表很大,与reduce端连接比较,map端的连接,不会产生大量数据的传递,而是在map端连接完毕之后就进行输出,效率极大的提高
连接方法:
(1)首先要重写Mapper类下面的setup方法,因为这个方法是先于map方法执行的,将较小的表先读入到一个HashMap中。
(2)重写map函数,一行行读入大表的内容,逐一的与HashMap中的内容进行比较,若Key相同,则对数据进行格式化处理,然后直接输出。
Reduce侧连接
使用分布式缓存API,完成两个数据集的连接操作
MapReduce连接取决于数据集的规模及分区方式
如果一个数据集很大而另外一个数据集很小,小的分发到集群中的每一个节点
mapper阶段读取大数据集中的数据
reducer获取本节点上的数据(也就是小数据集中的数据)并完成连接操作
步骤
将hdfs上的文件加入分布式缓存
URI cachepath = new Path("hdfs://master:9000/forms/address.dat").toUri();
job.setCacheFiles(new URI[]{cachepath});
之后在map/reduce函数中可以通过context来访问到缓存的文件,一般是重写setup方法来进行初始化
Map<String, String> addMap = new HashMap<String, String>();
protected void setup(Context context)
throws java.io.IOException, java.lang.InterruptedException {
URI uri = context.getCacheFiles()[0];
Path path = new Path(uri.toString());
Configuration conf = context.getConfiguration();
FileSystem fs = path.getFileSystem(conf);
@SuppressWarnings("resource")
LineReader linereader = new LineReader(fs.open(path));
Text t = new Text();
while(linereader.readLine(t) > 0) {
String[] tokens = t.toString().split(",");
if(tokens!=null && tokens.length==2)
addMap.put(tokens[0], tokens[1]);
}
}
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
if(values == null) return;
String v = addMap.get(values.iterator().next().toString());
out_key.set(key);
out_value.set(v);
context.write(out_key, out_value);
}
Map侧的连接
两个数据集中一个非常小,可以让小数据集存入缓存。在作业开始这些文件会被复制到运行task的节点上。 一开始,它的setup方法会检索缓存文件。
Map侧连接需要满足条件
与reduce侧连接不同,Map侧连接需要等待参与连接的数据集满足如下条件
1.除了连接键外,所有的输入都必须按照连接键排序。
输入的各种数据集必须有相同的分区数。
所有具有相同键的记录需要放在同一分区中。
当Map任务对其他Mapreduce作业的结果进行处理时(Cleanup时),Map侧的连接条件都自动满足
CompositeInputFormat类用于执行Map侧的连接,而输入和连接类型的配置可以通过属性指定
2.如果其中一个数据集足够小,旁路的分布式通道可以用在Map侧的连接中
总结
1.避免生成太多依赖I/O的map任务,数量由输入决定
2.作业加速主要来源于Map任务,有更高的并行度
3.Combiner对效率的提高,不仅在map reduce任务之间的数据传输,而且体现在降低了map侧I/O负载
4.自定义分区器可以在不同的reduce之间做负载均衡
5.分布式缓存对于小文件场景很有用,但应该避免过多或大的文件存储在缓存中