You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySpark:基于数组型订单ID列关联两个DataFrame的方法

问题:PySpark中如何将含订单ID数组的DataFrame关联订单DataFrame并生成嵌套订单列?

我是PySpark及DataFrame的新手,多次搜索都没找到解决方案。需要将profiles与orders两个DataFrame关联:profiles包含存储订单ID数组的ordersId列,希望为其新增orders列,该列包含与ordersId中ID对应的订单信息。

我尝试了如下代码,但因在where上下文无法访问withColumn中的ordersId数组,导致代码无法正常运行:

profiles = profiles.withColumn('orders', lit(orders.where(array_contains(profiles.ordersId, orders.id)).collect()))

示例数据

from pyspark.sql.types import StructType,StructField, StringType, IntegerType, ArrayType


data = [("aaaa", ['cc', 'dd'])]

schema = StructType([ \
    StructField("id", StringType(), False), \
    StructField("ordersId", ArrayType(StringType(), False), False), \
  ])
 
df = spark.createDataFrame(data=data, schema=schema)
df.printSchema()
df.show(truncate=False)


data2 = [("cc", "titi"), ("dd", "toto")]

schema2 = StructType([ \
    StructField("id", StringType(), False), \
    StructField("alias", StringType(), False), \
  ])
 
df2 = spark.createDataFrame(data=data2, schema=schema2)
df2.printSchema()
df2.show(truncate=False)

示例输出

root
 |-- id: string (nullable = false)
 |-- ordersId: array (nullable = false)
 |    |-- element: string (containsNull = false)

+----+--------+
|id  |ordersId|
+----+--------+
|aaaa|[cc, dd]|
+----+--------+

root
 |-- id: string (nullable = false)
 |-- alias: string (nullable = false)

+---+-----+
|id |alias|
+---+-----+
|cc |titi |
|dd |toto |
+---+-----+

期望结果

+----+--------+-----------------------------------------------+
|id  |ordersId|orders                                         |
+----+--------+-----------------------------------------------+
|aaaa|[cc, dd]|[{id: cc, alias: titi}, {id: dd, alias: toto}] |
+----+--------+-----------------------------------------------+

解决方案

你的问题在于直接在withColumn里调用collect()会把orders数据拉到Driver端,而且array_contains无法跨DataFrame直接关联。正确的做法是通过展开数组、关联、再聚合的方式实现:

方法一:使用explode+join+groupBy(通用版本)

from pyspark.sql import functions as F

# 1. 展开profiles中的ordersId数组,生成每行对应一个订单ID的临时表
exploded_profiles = df.withColumn("order_id", F.explode(F.col("ordersId")))

# 2. 和orders表关联,获取对应的订单信息
joined_df = exploded_profiles.join(df2, exploded_profiles.order_id == df2.id, "left")

# 3. 按profiles的id分组,将订单信息收集成数组
result = joined_df.groupBy("id", "ordersId")\
                  .agg(F.collect_list(F.struct(F.col("id").alias("id"), F.col("alias").alias("alias"))).alias("orders"))

result.show(truncate=False)

方法二:使用transform+映射字典(Spark 3.0+ 简洁版)

如果你的Spark版本是3.0及以上,可以用更简洁的方式,先把orders转成键值对映射,再匹配数组元素生成嵌套结构:

from pyspark.sql import functions as F

# 将orders表转成(id -> struct(id, alias))的映射字典
order_map = df2.groupBy().agg(F.map_from_entries(F.collect_list(F.struct(F.col("id"), F.struct(F.col("id"), F.col("alias"))))).alias("order_map")).first()["order_map"]

# 遍历ordersId数组,从映射中取出对应订单信息
result = df.withColumn("orders", F.transform(F.col("ordersId"), lambda x: order_map[x]))

result.show(truncate=False)

说明

  • 方法一适用于所有Spark版本,是分布式场景下的通用方案,不会把全量数据拉到Driver端,适合大数据量场景。
  • 方法二更简洁,但依赖Spark 3.0+,且如果orders数据量过大,first()会把映射字典拉到Driver端,更适合小体量的orders表。

内容的提问来源于stack exchange,提问作者Cariz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:06:45