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 在大数据处理中如何高效实现连接操作。

相关推荐
亚林瓜子1 天前
AWS中国云中的ETL之从Amazon Glue Data Catalog搬数据到MySQL(Glue版)
python·mysql·spark·etl·aws·glue·py
【赫兹威客】浩哥1 天前
【赫兹威客】伪分布式Spark测试教程
大数据·分布式·spark
yumgpkpm1 天前
在AI语言大模型时代 Cloudera CDP(华为CMP 鲲鹏版)对自有知识的保护
人工智能·hadoop·华为·zookeeper·spark·kafka
计算机毕业编程指导师1 天前
【Python大数据选题】基于Hadoop+Spark奥运会金牌榜可视化分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 数据挖掘
大数据·hadoop·python·计算机·spark·毕业设计·奥运会金牌
【赫兹威客】浩哥2 天前
【赫兹威客】完全分布式Spark测试教程
大数据·分布式·spark
鸿乃江边鸟2 天前
Spark Datafusion Comet 向量化Rule--CometExecRule分析 规则转换分析
大数据·spark·native
Light602 天前
领码 SPARK aPaaS 前端开发体系 技术架构(最终版)
低代码·spark·前端架构·apaas·模型驱动·能力分层·上下文契约
【赫兹威客】浩哥2 天前
【赫兹威客】完全分布式Hive(on Spark)测试教程
hive·分布式·spark
Gain_chance2 天前
19-学习笔记尚硅谷数仓搭建-数据仓库运行环境搭建(spark安装及配置)
数据仓库·笔记·学习·spark
麦兜和小可的舅舅3 天前
Spark to ClickHouse由于DNS问题导致Stage重试的Task竞态分析和问题解决过程
clickhouse·spark