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

Spark 2.3中如何实现arrays_zip等效功能?

在Spark 2.3中实现arrays_zip的等效功能

Spark 2.4才正式引入arrays_zip函数,2.3版本里确实没有这个内置工具,但我们可以通过两种实用的方式复刻它的核心功能,下面分别介绍:

方法一:利用posexplode和分组聚合(无UDF方案)

这种方法完全依赖Spark原生SQL函数,避免了UDF可能带来的性能开销,核心思路是把数组按位置炸开后重新聚合:

from pyspark.sql import SparkSession
from pyspark.sql.functions import posexplode, monotonically_increasing_id, collect_list, struct

# 初始化SparkSession
spark = SparkSession.builder.appName("arrays_zip_emulation").getOrCreate()

# 创建和官方示例一致的测试数据
df = spark.createDataFrame([(([1, 2, 3], [2, 3, 4]))], ['vals1', 'vals2'])

# 步骤1:添加唯一行标识,用来区分不同数据行
df_with_id = df.withColumn("row_id", monotonically_increasing_id())

# 步骤2:对每个数组列执行posexplode,提取位置索引和对应元素
df_explode_vals1 = df_with_id.select("row_id", posexplode("vals1").alias("pos", "vals1_val"))
df_explode_vals2 = df_with_id.select("row_id", posexplode("vals2").alias("pos", "vals2_val"))

# 步骤3:按行ID和位置关联,打包成struct后再按行ID聚合回数组
zipped_df = df_explode_vals1.join(df_explode_vals2, on=["row_id", "pos"], how="inner") \
    .groupBy("row_id") \
    .agg(collect_list(struct("vals1_val", "vals2_val")).alias("zipped")) \
    .drop("row_id")

# 查看结果
zipped_df.show(truncate=False)

运行后会得到和Spark 2.4arrays_zip完全一致的输出:

+----------------------------------------+
|zipped                                  |
+----------------------------------------+
|[{1, 2}, {2, 3}, {3, 4}]                |
+----------------------------------------+

方法二:使用自定义UDF(Python层面处理)

如果更习惯Python的逻辑,也可以写一个UDF来模拟arrays_zip的行为,注意要和官方函数保持一致:当输入数组长度不一致时,取最短数组的长度作为结果数组的长度。

from pyspark.sql import SparkSession
from pyspark.sql.functions import udf
from pyspark.sql.types import ArrayType, StructType, StructField, IntegerType

# 初始化SparkSession
spark = SparkSession.builder.appName("arrays_zip_udf").getOrCreate()

# 定义和输入列匹配的StructType,这里对应两个Integer类型的字段
zip_schema = ArrayType(StructType([
    StructField("vals1", IntegerType()),
    StructField("vals2", IntegerType())
]))

# 实现UDF逻辑:用Python的zip函数打包,再转成字典列表(对应Spark的struct)
def arrays_zip_udf(arr1, arr2):
    # 处理空数组的情况,和官方行为对齐
    if not arr1 or not arr2:
        return []
    # 取最短数组的长度,和Spark 2.4的arrays_zip行为一致
    min_len = min(len(arr1), len(arr2))
    return [{"vals1": arr1[i], "vals2": arr2[i]} for i in range(min_len)]

# 注册UDF
zip_udf = udf(arrays_zip_udf, zip_schema)

# 创建测试数据
df = spark.createDataFrame([(([1, 2, 3], [2, 3, 4]))], ['vals1', 'vals2'])

# 调用UDF
result_df = df.select(zip_udf(df.vals1, df.vals2).alias("zipped"))

# 查看结果
result_df.show(truncate=False)

这个方法的输出和官方函数完全一致,而且可以轻松扩展到更多数组列的情况(只需要修改schema和UDF的参数即可)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 13:37:32