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

PySpark:将键值结构体数组转换为单个结构体

键值结构体数组转预定义Person结构体(PySpark高性能实现)

需求说明

现有一列数据为任意长度的键值结构体数组,需将其转换为预定义的Person结构体列。要求仅使用pyspark.sql.functions内置方法,禁止使用Python UDF,确保能高效处理数十亿行数据。

数据结构定义

输入列Schema

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

input_schema = StructType([
    StructField("input_column", ArrayType(StructType([
        StructField("key", StringType(), False),
        StructField("value", StructType([
            StructField("string_value", StringType(), True),
            StructField("int_value", IntegerType(), True),
            StructField("float_value", FloatType(), True),
            StructField("double_value", DoubleType(), True)
        ]), True)
    ])), True)
])

目标Person结构体Schema

person_schema = StructType([
    StructField("first_name", StringType(), True),
    StructField("middle_name", StringType(), True),
    StructField("last_name", StringType(), True),
    StructField("birth_year", IntegerType(), True),
    StructField("ssn", IntegerType(), True),
    StructField("zipcode", IntegerType(), True),
])

输入输出示例

输入示例

[
    (key: "first_name", value: (string_value: "John")),
    (key: "ssn",        value: (int_value:    123456789)),
    (key: "last_name",  value: (string_value: "Doe")),
]
------------------------------------------------------
[
    (key: "ssn",        value: (int_value:    987654321)),
    (key: "last_name",  value: (string_value: "Jones")),
]
------------------------------------------------------
[
    (key: "zipcode",    value: (int_value:    13579)),
    (key: "first_name", value: (string_value: "Bob")),
    (key: "birth_year", value: (int_value:    1985)),
    (key: "last_name",  value: (string_value: "Smith")),
]

期望输出

{
    first_name: "John",
    last_name:  "Doe",
    ssn:        123456789
}
------------------------------------------------------
{
    last_name:  "Jones",
    ssn:        987654321
}
------------------------------------------------------
{
    first_name: "Bob",
    last_name:  "Smith",
    birth_year: 1985,
    zipcode:    13579
}

实现方案

核心思路是先将键值数组转换为Map类型,再从Map中提取对应字段组装成目标结构体,全程使用Spark内置矢量化函数保证性能。

完整代码

from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, FloatType, DoubleType, ArrayType
from pyspark.sql import functions as F

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

# 定义输入Schema
input_schema = StructType([
    StructField("input_column", ArrayType(StructType([
        StructField("key", StringType(), False),
        StructField("value", StructType([
            StructField("string_value", StringType(), True),
            StructField("int_value", IntegerType(), True),
            StructField("float_value", FloatType(), True),
            StructField("double_value", DoubleType(), True)
        ]), True)
    ])), True)
])

# 构造测试数据
test_data = [
    ([
        {"key": "first_name", "value": {"string_value": "John", "int_value": None, "float_value": None, "double_value": None}},
        {"key": "ssn", "value": {"string_value": None, "int_value": 123456789, "float_value": None, "double_value": None}},
        {"key": "last_name", "value": {"string_value": "Doe", "int_value": None, "float_value": None, "double_value": None}}
    ],),
    ([
        {"key": "ssn", "value": {"string_value": None, "int_value": 987654321, "float_value": None, "double_value": None}},
        {"key": "last_name", "value": {"string_value": "Jones", "int_value": None, "float_value": None, "double_value": None}}
    ],),
    ([
        {"key": "zipcode", "value": {"string_value": None, "int_value": 13579, "float_value": None, "double_value": None}},
        {"key": "first_name", "value": {"string_value": "Bob", "int_value": None, "float_value": None, "double_value": None}},
        {"key": "birth_year", "value": {"string_value": None, "int_value": 1985, "float_value": None, "double_value": None}},
        {"key": "last_name", "value": {"string_value": "Smith", "int_value": None, "float_value": None, "double_value": None}}
    ],)
]

df = spark.createDataFrame(test_data, schema=input_schema)

# 执行转换
df_transformed = df.withColumn(
    # 转换数组元素:提取key和对应类型的value
    "transformed_entries",
    F.transform(
        "input_column",
        lambda x: F.struct(
            x.key.alias("key"),
            F.when(x.key.isin("first_name", "middle_name", "last_name"), x.value.string_value)
             .when(x.key.isin("birth_year", "ssn", "zipcode"), x.value.int_value)
             .alias("value")
        )
    )
).withColumn(
    # 将转换后的数组转为Map
    "data_map",
    F.map_from_entries(F.col("transformed_entries"))
).withColumn(
    # 从Map中提取字段组装成Person结构体
    "person",
    F.struct(
        F.col("data_map").getItem("first_name").alias("first_name"),
        F.col("data_map").getItem("middle_name").alias("middle_name"),
        F.col("data_map").getItem("last_name").alias("last_name"),
        F.col("data_map").getItem("birth_year").cast(IntegerType()).alias("birth_year"),
        F.col("data_map").getItem("ssn").cast(IntegerType()).alias("ssn"),
        F.col("data_map").getItem("zipcode").cast(IntegerType()).alias("zipcode")
    )
).drop("transformed_entries", "data_map")

# 查看结果
df_transformed.select("person").show(truncate=False)

性能说明

  • 全程使用Spark内置的transform、map_from_entries、struct等矢量化函数,避免了Python UDF的序列化/反序列化开销,适合处理大规模数据。
  • 逻辑清晰,每一步都是Spark优化后的算子,能充分利用集群资源并行处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:07:10