Hadoop 中连接(join)操作很常见,Hadoop“连接” 的概念本身,和 SQL 的 “连接” 是一致的。SQL 的连接,在维基百科中已经说得非常清楚。比如 dataset A 是关于用户个人信息的,key 是用户 id,value 是用户姓名等等个人信息;dataset B 是关于用户交易记录的,key 是用户 id,value 是用户的交易历史等信息。我们当然可以对这两者以共同键用户 id 为基准来连接两边的数据。
首先,在一切开始之前,先确定真的需要使用 Hadoop 的连接操作吗?
如果要把两个数据集合放到一起操作,Hadoop 还提供了 Side Data Distribution(data sharing)的方式,这种方式对于小数据量的情况下效率要高得多,说白了就是把某些数据缓存到本地,例如在本地内存中,直接操作执行,具体包括两种子方式:
- 使用 Job Configuration 传递;
- 使用 Distributed Cache。
当数据量比较大时,是不适合采用 Side Data Distribution 的,这时候就需要考虑 Join 了。
Map-side Join
Map-side Join 会将数据从不同的 dataset 中取出,连接起来并放到相应的某个 Mapper 中处理,因此 key 相同的数据肯定会在同一个 Mapper 里面一起得到处理的。如果 Mapper 前 dataset 中的数据是无序的,那么对于 dataset A 的任意一个 key,要到其它的 dataset 中寻找该 key 对应的数据,造成的复杂度是 n 的 x 次方,x 等于 dataset 的个数。因此要求 dataset 是有序的,这样每个对于任何一个 Mapper 来说,每一个 dataset 都只需要遍历一次就可以取到所有需要的数据。Map-side Join 对 dataset 的限制很多,进入不仅仅是有序,不同的 dataset 中数据的 partition 方式也要一致,其实最终目的就是保证同样 key 的数据同时进入一个 Mapper。
Reduce-side Join
Reduce-side Join 原理上要简单得多,它也不能保证相同 key 但分散在不同 dataset 中的数据能够进入同一个 Mapper,整个数据集合的排序在 Mapper 之后的 shuffle 过程中完成。相对于 Map-side Join,它不需要每个 Mapper 都去读取所有的 dataset,这是好处,但也有坏处,即这样一来 Mapper 之后需要排序的数据集合会非常大,因此 shuffle 阶段的效率要低于 Map-side Join。如果希望在 shuffle 之后,进入 Reducer 的时候,value 列表是有序的,那么就需要使用 Hadoop 的 Secondary Sort(移步此文)。
不管使用 Map-side Join 还是 Reduce-side Join,都要求进行 Join 的数据满足某一抽象,这个抽象类型即为进入 Mapper 或者 Reducer 的 input key 的类型。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》