附录D.2 复制连接框架

复制连接是map端连接,得名于它的具体实现:连接中最小的数据集将会被复制到所有的map主机节点。复制连接的实现非常直接明了。更具体的内容可以参考Chunk Lam的《Hadoop in Action》。

这个部分的目标是:创建一个可以支持任意类型的数据集的通用的复制连接框架。这个框架中提供了一个优化的小功能:动态监测分布式缓存内容和输入块的大小,并判断哪个更大。如果输入块较小,那么你就需要将map的输入块放到内存缓冲中,然后在map的cleanup方法中执行连接操作了。

图D.4是这个框架的类图,这里提供了连接类(GenericReplicatedJoin)的具体实现,而不仅仅是一个抽象类。在这个框架外,这个类将和KeyValueTextInputFormat及TextOutputFormat协作。它的一个假设前提是:每个数据文件的第一个标记是连接键。此外,连接类也可以被继承扩展来支持任意类型的输入和输出。

图D.5是连接框架的算法。Map的setup方法判断在map的输入块和分布式缓存中的内容哪个大。如果分布式缓存的内容比较小,那么它将被装载到内存缓存中。然后在Map函数开始连接操作。如果输入块比较小,map函数将输入块的键\值对装载到内存缓存中。Map的cleanup方法将从分布式缓存中读取记录,逐条记录和在内存缓存中的键\值对进行连接操作。

以下代码是GenericReplicatedJoin类中setup方法。它在map的初始化阶段被调用的。这个方法判断分布式缓存中的文件和输入块哪个大。如果文件比较小,则将文件装载到HashMap中。

 1 @Override
2 protected void setup(Context context)
3 throws IOException, InterruptedException {
4
5 distributedCacheFiles = DistributedCache.getLocalCacheFiles(context.getConfiguration());
6 int distCacheSizes = 0;
7
8 for (Path distFile : distributedCacheFiles) {
9 File distributedCacheFile = new File(distFile.toString());
10 distCacheSizes += distributedCacheFile.length();
11 }
12
13 if(context.getInputSplit() instanceof FileSplit) {
14 FileSplit split = (FileSplit) context.getInputSplit();
15 long inputSplitSize = split.getLength();
16 distributedCacheIsSmaller = (distCacheSizes < inputSplitSize);
17 } else {
18 distributedCacheIsSmaller = true;
19 }
20
21 if (distributedCacheIsSmaller) {
22 for (Path distFile : distributedCacheFiles) {
23 File distributedCacheFile = new File(distFile.toString());
24 DistributedCacheFileReader reader = getDistributedCacheReader();
25 reader.init(distributedCacheFile);
26
27 for (Pair p : (Iterable<Pair>) reader) {
28 addToCache(p);
29 }
30
31 reader.close();
32 }
33 }
34 }

根据setup方法是否将分布式缓存的内容装载到内存的缓存中,Map方法将会有不同的行为。如果分布式缓存中的内容被装载到内存中,那么map方法就将输入块的记录和内存中的缓存做连接操作。如果分布式缓存中的内容没有被装载到内存中,那么map方法就将输入块的记录装载到内存中,然后在cleanup方法中使用。

 1 @Override
2 protected void map(Object key, Object value, Context context)
3 throws IOException, InterruptedException {
4 Pair pair = readFromInputFormat(key, value);
5
6 if (distributedCacheIsSmaller) {
7 joinAndCollect(pair, context);
8 } else {
9 addToCache(pair);
10 }
11 }
12
13 public void joinAndCollect(Pair p, Context context)
14 throws IOException, InterruptedException {
15 List<Pair> cached = cachedRecords.get(p.getKey());
16
17 if (cached != null) {
18 for (Pair cp : cached) {
19 Pair result;
20
21 if (distributedCacheIsSmaller) {
22 result = join(p, cp);
23 } else {
24 result = join(cp, p);
25 }
26
27 if (result != null) {
28 context.write(result.getKey(), result.getData());
29 }
30 }
31 }
32 }
33
34 public Pair join(Pair inputSplitPair, Pair distCachePair) {
35 StringBuilder sb = new StringBuilder();
36
37 if (inputSplitPair.getData() != null) {
38 sb.append(inputSplitPair.getData());
39 }
40
41 sb.append("\t");
42
43 if (distCachePair.getData() != null) {
44 sb.append(distCachePair.getData());
45 }
46
47 return new Pair<Text, Text>(
48 new Text(inputSplitPair.getKey().toString()),
49 new Text(sb.toString()));
50 }

当所有的记录都被传输给map方法后,MapReduce将会调用cleanup方法。如果分布式缓存中的内容比输入块大,连接将会在cleanup中进行。连接的对象是map函数的缓存中的输入块的记录和分布式缓存中的记录。

 1 @Override
2 protected void cleanup(Context context)
3 throws IOException, InterruptedException {
4
5 if (!distributedCacheIsSmaller) {
6
7 for (Path distFile : distributedCacheFiles) {
8 File distributedCacheFile = new File(distFile.toString());
9 DistributedCacheFileReader reader = getDistributedCacheReader();
10 reader.init(distributedCacheFile);
11
12 for (Pair p : (Iterable<Pair>) reader) {
13 joinAndCollect(p, context);
14 }
15
16 reader.close();
17 }
18 }
19 }

最后,作业的驱动代码必须指定需要装载到分布式缓存中的文件。以下的代码可以处理一个文件,也可以处理MapReduce输入结果的一个目录。

 1 Configuration conf = new Configuration();
2
3 FileSystem fs = smallFilePath.getFileSystem(conf);
4 FileStatus smallFilePathStatus = fs.getFileStatus(smallFilePath);
5
6 if(smallFilePathStatus.isDir()) {
7 for(FileStatus f: fs.listStatus(smallFilePath)) {
8 if(f.getPath().getName().startsWith("part")) {
9 DistributedCache.addCacheFile(f.getPath().toUri(), conf);
10 }
11 }
12 } else {
13 DistributedCache.addCacheFile(smallFilePath.toUri(), conf);
14 }

这个框架假设分布式缓存中的内容和输入块的内容都可以被装载到内存中。它的优点在于两个数据集之中较小的才会装载到内存中。

在论文《A Comparison of Join Algorithms for Log Processing in MapReduce》中,针对对于分布式缓存中的内容较大时的场景对这个方法进行了更多的优化。在他们的优化中,他们将分布式缓存分成N个分区,并将输入块放入N个哈希表。然后在cleanup方法中的优化就更加高效。

在map端的复制连接的问题在于,map任务必须在启动时读取分布式缓存。上述论文提到的另一个优化方案是重载FileInputFormat的splitting。将存在于同一个主机上的输入块合并成一个块。然后就可以减少需要装载分布式缓存的map任务的个数了。

最后一个说明,Hadoop在org.apache.hadoop.mapred.join包中自带了map端的连接。但是它需要有序的待连接的数据集的输入文件,并要求将其分发到相同的分区中。这样就造成了繁重的预处理工作。

[大牛翻译系列]Hadoop(22)附录D.2 复制连接框架的更多相关文章

  1. [大牛翻译系列]Hadoop 翻译文章索引

    原书章节 原书章节题目 翻译文章序号 翻译文章题目 链接 4.1 Joining Hadoop(1) MapReduce 连接:重分区连接(Repartition join) http://www.c ...

  2. [大牛翻译系列]Hadoop(3)MapReduce 连接:半连接(Semi-join)

    4.1.3 半连接(Semi-join) 假设一个场景,需要连接两个很大的数据集,例如,用户日志和OLTP的用户数据.任何一个数据集都不是足够小到可以缓存在map作业的内存中.这样看来,似乎就不能使用 ...

  3. [大牛翻译系列]Hadoop(2)MapReduce 连接:复制连接(Replication join)

    4.1.2 复制连接(Replication join) 复制连接是map端的连接.复制连接得名于它的具体实现:连接中最小的数据集将会被复制到所有的map主机节点.复制连接有一个假设前提:在被连接的数 ...

  4. [大牛翻译系列]Hadoop(21)附录D.1 优化后的重分区框架

    附录D.1 优化后的重分区框架 Hadoop社区连接包需要将每个键的所有值都读取到内存中.如何才能在reduce端的连接减少内存开销呢?本文提供的优化中,只需要缓存较小的数据集,然后在连接中遍历较大数 ...

  5. [大牛翻译系列]Hadoop(1)MapReduce 连接:重分区连接(Repartition join)

    4.1 连接(Join) 连接是关系运算,可以用于合并关系(relation).对于数据库中的表连接操作,可能已经广为人知了.在MapReduce中,连接可以用于合并两个或多个数据集.例如,用户基本信 ...

  6. [大牛翻译系列]Hadoop(20)附录A.10 压缩格式LZOP编译安装配置

    附录A.10 LZOP LZOP是一种压缩解码器,在MapReduce中可以支持可分块的压缩.第5章中有一节介绍了如何应用LZOP.在这一节中,将介绍如何编译LZOP,在集群做相应配置. A.10.1 ...

  7. [大牛翻译系列]Hadoop(19)MapReduce 文件处理:基于压缩的高效存储(二)

    5.2 基于压缩的高效存储(续) (仅包括技术27) 技术27 在MapReduce,Hive和Pig中使用可分块的LZOP 如果一个文本文件即使经过压缩后仍然比HDFS的块的大小要大,就需要考虑选择 ...

  8. [大牛翻译系列]Hadoop(18)MapReduce 文件处理:基于压缩的高效存储(一)

    5.2 基于压缩的高效存储 (仅包括技术25,和技术26) 数据压缩可以减小数据的大小,节约空间,提高数据传输的效率.在处理文件中,压缩很重要.在处理Hadoop的文件时,更是如此.为了让Hadoop ...

  9. [大牛翻译系列]Hadoop(17)MapReduce 文件处理:小文件

    5.1 小文件 大数据这个概念似乎意味着处理GB级乃至更大的文件.实际上大数据可以是大量的小文件.比如说,日志文件通常增长到MB级时就会存档.这一节中将介绍在HDFS中有效地处理小文件的技术. 技术2 ...

随机推荐

  1. json,xml,Html解析

    1.json解析 javabean文件 public class TopNewsDetails { public String retcode; public Data data; public cl ...

  2. iOS 生成随机数 重复 不重复

    //编程的时候,有三条任选执行路径,都会显示一些图片,比如路径1显示的图片是一个人,路径2显示的是两个人,路径3显示任意人数的图片,要求每次进入该页面都不能重复初始的那张图片. 于是我想到了 运用随机 ...

  3. MVC框架 - 高级示例

    在第一个MVC教程章中,我们学会了如何在MVC控制器和视图进行交互.在本教程中,我们将向前更进一步,学习如何使用模型创建高级应用程序来创建,编辑,删除用户,在我们的应用程序中查看列表. 下面是用来创建 ...

  4. In-Memory:Hash Index

    SQL Server 2016支持哈希查找,用户可以在内存优化表(Memory-Optimized Table)上创建Hash Index,使用Hash 查找算法,实现数据的极速查找.在使用上,Has ...

  5. iOS 设计模式之单例

    设计模式:单例 一.  单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并 ...

  6. JAVA 多态的一种实现

    今天一个同事问我一个问题,就是关于子类,父类之间方法的调用这里的.这里我整理了一个小DEMO. 代码如下: 父类的代码: public abstract class ClassA { public f ...

  7. 如何使用 SQL Developer 导出数据

    完成此方法文档后,您应该能够了解: 如何使用 SQL Developer 将数据导出为各种文件格式 如何导出模式中的对象定义 目录 1. 简介 2. 软件要求 3. 导出数据 4. 导出对象定义 5. ...

  8. a different object with the same identifier value was already associated withthe session异常解决方案

    异常信息: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was ...

  9. python备忘录

    本文主要是记录一下python,比较详尽的python学习资料: Python学习笔记_王纯业 http://pan.baidu.com/s/1eQrDEYA 部分有详细的博文链接 1.字符串: 切片 ...

  10. Android apk 的安装过程

    Android应用安装有如下四种方式 1.系统应用安装――开机时完成,没有安装界面 2.网络下载应用安装――通过market应用完成,没有安装界面 3.ADB工具安装――没有安装界面. 4.第三方应用 ...