Spark RDD各种join算子从源码层分析实现方式

在 Spark RDD 中,joinleftOuterJoinrightOuterJoinfullOuterJoin 等多个 Join 操作符都使用了 cogroup 进行底层实现。cogroup 是 Spark 中的一种底层分组操作,可以将两个或多个 RDD 中同一键的数据分组到一起,为各种 Join 操作提供了基础。下面我们从源码实现角度来分析这些 Join 操作符的实现原理,并列出相关的核心代码。

1. join

join 是最常用的连接操作,它会返回两个 RDD 中键相同的元素对。join 操作底层依赖 cogroup 实现:

scala 复制代码
def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))] = {
  this.cogroup(other, numPartitions).flatMapValues {
    case (vs, ws) => for (v <- vs.iterator; w <- ws.iterator) yield (v, w)
  }
}

实现过程

  1. cogroup 将两个 RDD 中相同的键的数据组合成 (K, (Iterable[V], Iterable[W])) 形式。
  2. 然后通过 flatMapValues 遍历所有相同键的值对 (v, w),形成最终的 (K, (V, W)) 格式。

示例

python 复制代码
rdd1 = sc.parallelize([("a", 1), ("b", 2)])
rdd2 = sc.parallelize([("a", 3), ("b", 4)])
joined = rdd1.join(rdd2)
print(joined.collect())
# 输出: [('a', (1, 3)), ('b', (2, 4))]

2. leftOuterJoin

leftOuterJoin 会返回左侧 RDD 的所有键,并对右侧 RDD 中匹配的键进行连接,未匹配到的则返回 None

scala 复制代码
def leftOuterJoin[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, Option[W]))] = {
  this.cogroup(other, numPartitions).flatMapValues {
    case (vs, ws) =>
      if (ws.isEmpty) vs.iterator.map(v => (v, None))
      else for (v <- vs.iterator; w <- ws.iterator) yield (v, Some(w))
  }
}

实现过程

  1. 使用 cogroup 分组得到 (K, (Iterable[V], Iterable[W])) 格式。
  2. 对于左侧 RDD 的值 vs,如果右侧 RDD 的 ws 为空,则返回 None;否则返回 (v, Some(w))

示例

python 复制代码
rdd1 = sc.parallelize([("a", 1), ("b", 2)])
rdd2 = sc.parallelize([("a", 3)])
left_joined = rdd1.leftOuterJoin(rdd2)
print(left_joined.collect())
# 输出: [('a', (1, Some(3))), ('b', (2, None))]

3. rightOuterJoin

rightOuterJoin 返回右侧 RDD 的所有键,未匹配的左侧 RDD 值则为 None

scala 复制代码
def rightOuterJoin[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (Option[V], W))] = {
  this.cogroup(other, numPartitions).flatMapValues {
    case (vs, ws) =>
      if (vs.isEmpty) ws.iterator.map(w => (None, w))
      else for (v <- vs.iterator; w <- ws.iterator) yield (Some(v), w)
  }
}

实现过程

  1. cogroup 将两个 RDD 分组。
  2. 对右侧 RDD 中的值 ws,如果左侧 RDD 中 vs 为空,则返回 None;否则返回 (Some(v), w)

示例

python 复制代码
rdd1 = sc.parallelize([("a", 1)])
rdd2 = sc.parallelize([("a", 3), ("b", 4)])
right_joined = rdd1.rightOuterJoin(rdd2)
print(right_joined.collect())
# 输出: [('a', (Some(1), 3)), ('b', (None, 4))]

4. fullOuterJoin

fullOuterJoin 会返回左右两个 RDD 的所有键。未匹配的键对应的值为 None

scala 复制代码
def fullOuterJoin[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (Option[V], Option[W]))] = {
  this.cogroup(other, numPartitions).flatMapValues {
    case (vs, ws) =>
      if (vs.isEmpty) ws.iterator.map(w => (None, Some(w)))
      else if (ws.isEmpty) vs.iterator.map(v => (Some(v), None))
      else for (v <- vs.iterator; w <- ws.iterator) yield (Some(v), Some(w))
  }
}

实现过程

  1. 使用 cogroup 进行键的分组。
  2. 对于每个键的 vsws,分别判断它们是否为空,如果为空则返回 None

示例

python 复制代码
rdd1 = sc.parallelize([("a", 1), ("b", 2)])
rdd2 = sc.parallelize([("a", 3), ("c", 4)])
full_joined = rdd1.fullOuterJoin(rdd2)
print(full_joined.collect())
# 输出: [('a', (Some(1), Some(3))), ('b', (Some(2), None)), ('c', (None, Some(4)))]

cogroup 的作用

cogroup 是 Spark 中连接操作的核心,通过对两个或多个 RDD 进行键分组,将相同键的数据放到一个集合中,使得不同类型的 Join 操作能够灵活实现。通过 cogroup,Spark 可以高效地将键相同的值合并在一起,而不需要在每个连接操作中重写分组逻辑。

总结

  • 底层共用 :所有 join 操作都使用 cogroup 进行分组,然后通过对分组后的键值对进行遍历和组合来实现不同的 Join 类型。
  • 性能优化cogroup 提供了键值对的高效分组机制,减少了 Join 操作中的数据传输量,从而提升了连接操作的性能。

这几种 Join 操作的实现逻辑和底层调用可以帮助我们理解 Spark 在大数据处理中如何高效实现连接操作。

相关推荐
向哆哆19 小时前
深入解析华为 CANN Matmul 高阶算子:数据流、NZ 格式与完整 Tiling 策略全解
算子·昇腾·cann
向哆哆19 小时前
深入解析华为CANN算子开发:从异构并行到核函数编程
算子·昇腾·cann
向哆哆1 天前
深入理解华为 CANN 中的 Broadcast 算子实现:从底层机制到工程化落地
华为·算子·昇腾·cann
向哆哆1 天前
深入解析华为CANN Matmul算子:从数据流到高性能实现
算子·昇腾·cann
pale_moonlight1 天前
九、Spark基础环境实战((上)虚拟机安装Scala与windows端安装Scala)
大数据·分布式·spark
向哆哆1 天前
深入理解华为CANN静态Tensor编程范式:极致性能的算子开发之道
华为·算子·昇腾·cann
青云交3 天前
Java 大视界 -- Java 大数据在智能物流无人配送车路径规划与协同调度中的应用
java·spark·路径规划·大数据分析·智能物流·无人配送车·协同调度
wuli_滔滔4 天前
昇腾Atlas加速卡与Ascend C:从硬件基石到编程哲学的深度解析与实战
算子·昇腾·atlas·ascend c·cann]
yumgpkpm4 天前
腾讯云TBDS与CDH迁移常见问题有哪些?建议由CDH迁移到CMP 7.13 平台(类Cloudera CDP,如华为鲲鹏 ARM 版)
hive·hadoop·zookeeper·flink·spark·kafka·hbase
bigdata-rookie5 天前
Spark 部署模式
大数据·分布式·spark