在 Hadoop 生态体系里,对数据集的 Join 操作可能是最重要的操作之一了。因此了解 Hadoop 中的 Join 的实现原理从下面几个方面来考虑是很有必要的:

  • 在实际场景中该使用哪种 Join 策略;
  • Join 过程中遇到问题该如何 debug;
  • 更好地使用 Hive;
  • 在需要更细粒度的操作时可以手撸代码。

总的来说,Hadoop 中的 Join 可以分为 2 类:

  • Reduce-Side
  • Map-Side

Reduce Side Joins

这种模式的 Join 操作在每个 Reducer 中进行而不是在 mapper 中。

在三种 Join 模式中,这是最容易实现的一种,因为 排序和 shuffle 的过程全部由 MapReduce 框架帮助完成了

基本上,Reduce Side Join 操作的顺序如下所示:

  • Mapper 读入数据,以 join column 为 key;
  • mapper 给输入的数据打上标签: 这条数据属于哪个数据集或者数据库
  • mapper 输出的中间键值对的键就是 join column;
  • MapReduce 框架对中间键值对做排序和 shuffle 处理,输出的 join column 键和对应的值列表会被当做 reducer 的输入;
  • reducer 对输入的数据做接下来的聚合处理。

具体的代码参见 这个 Repo

结论

Reduce Side Join 实现简单,逻辑清晰,而且对 map 的输入数据几乎没有任何限制。
但是,在 reducer 端做 join 有很大的问题,由于完全将 sort 和 shuffle 操作交给 MapReduce 框架实现,因此会占用大量(昂贵的)带宽资源,并且当数据量大的时候会占用很多内存资源,极有可能造成 OutOfMemory Exception

Map Side Join

假设有两个表,其中一个表的数据量比较小。在 Map Side Join中:

  1. 一个本地的 MapReduce 任务会先把小的表的数据文件读到一个内存 Hash 表中,然后会将这个表中的数据序列化到一个Hash 表文件中。
    这一步的必要性在于:如果没有 cache, 当有几千个 mapper 同时向 HDFS 读取原始小表数据时,这个过程必将成为瓶颈。

  2. 原始的 MapReduce 任务将存在 Hash 表文件 中的数据转移到 Hadoop 分布式缓存中,然后将这些文件发送到每个 mapper 的本地磁盘上;

  3. 每个 mapper 将存在本地的小表数据序列化到内存中然后做 join 操作。

优缺点

优点

缺点

  • 只有当两个表中的一个小到足以塞进 mapper 的 内存中时才有用。