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

PySpark DataFrame Schema转换:将Struct内数组转为字符串

解决PySpark DataFrame结构体中数组转字符串的类型转换问题

问题背景

通过以下代码生成了PySpark DataFrame df_array:

df_array = (df_csv.groupBy(df_csv.depth,df_csv.height,df_csv.weight,df_csv.width,df_csv.seller_id,df_csv.sku,df_csv.navigation_id,df_csv.category, 
                         df_csv.subcategory,df_csv.max_dimension_p,df_csv.max_side_p)
                         .agg(sf.struct(sf.collect_list('id_distribution_center').alias('id_distribution_center'),sf.collect_list('id_modality').alias('id_modality'),
                                    sf.collect_list('zipcode_initial').alias('zipcode_initial'),sf.collect_list('zipcode_final').alias('zipcode_final'),sf.collect_list('cost').alias('cost'),sf.collect_list('city').alias('city'),sf.collect_list('state').alias('state')).alias("infos_gerais_product")))

该DataFrame的原始schema如下:

root
 |-- depth: double (nullable = true)
 |-- height: double (nullable = true)
 |-- weight: double (nullable = true)
 |-- width: double (nullable = true)
 |-- seller_id: string (nullable = true)
 |-- sku: long (nullable = true)
 |-- navigation_id: long (nullable = true)
 |-- category: string (nullable = true)
 |-- subcategory: string (nullable = true)
 |-- max_dimension_p: double (nullable = true)
 |-- max_side_p: double (nullable = true)
 |-- infos_gerais_product: struct (nullable = false)
 |    |-- id_distribution_center: array (nullable = false)
 |    |    |-- element: long (containsNull = false)
 |    |-- id_modality: array (nullable = false)
 |    |    |-- element: long (containsNull = false)
 |    |-- zipcode_initial: array (nullable = false)
 |    |    |-- element: long (containsNull = false)
 |    |-- zipcode_final: array (nullable = false)
 |    |    |-- element: long (containsNull = false)
 |    |-- cost: array (nullable = false)
 |    |    |-- element: double (containsNull = false)
 |    |-- city: array (nullable = false)
 |    |    |-- element: string (containsNull = false)
 |    |-- state: array (nullable = false)
 |    |    |-- element: string (containsNull = false)

需要将infos_gerais_product结构体中的数组类型转换为字符串类型,目标schema如下:

|-- depth: double (nullable = true)
 |-- height: double (nullable = true)
 |-- weight: double (nullable = true)
 |-- width: double (nullable = true)
 |-- seller_id: string (nullable = true)
 |-- sku: long (nullable = true)
 |-- navigation_id: long (nullable = true)
 |-- category: string (nullable = true)
 |-- subcategory: string (nullable = true)
 |-- max_dimension_p: double (nullable = true)
 |-- max_side_p: double (nullable = true)
 |-- infos_gerais_product: struct (nullable = false)
 |    |-- id_distribution_center: string (nullable = false)
 |    |-- id_modality: string (nullable = false)
 |    |-- zipcode_initial: string (nullable = false)
 |    |-- zipcode_final: string (nullable = false)
 |    |-- cost: string (nullable = false)
 |    |-- city: string (nullable = false)
 |    |-- state: string (nullable = false)

尝试通过重新定义schema并使用spark.createDataFrame转换时,出现报错:

TypeError: data is already a DataFrame

错误原因

spark.createDataFrame()的第一个参数需要是RDD、列表等原始数据源,而非已存在的DataFrame。直接传入已有的DataFrame会触发类型错误,因为该方法不支持直接基于现有DataFrame重新指定schema。

解决方案

有两种可行的方式实现类型转换:

方式1:修改聚合逻辑,直接生成字符串类型字段

在agg阶段,将collect_list生成的数组直接通过array_join转换为字符串(用指定分隔符拼接数组元素),这样生成的结构体字段默认就是字符串类型:

df_array = (df_csv.groupBy(
    df_csv.depth, df_csv.height, df_csv.weight, df_csv.width,
    df_csv.seller_id, df_csv.sku, df_csv.navigation_id,
    df_csv.category, df_csv.subcategory, df_csv.max_dimension_p, df_csv.max_side_p
).agg(
    sf.struct(
        sf.array_join(sf.collect_list('id_distribution_center'), ",").alias('id_distribution_center'),
        sf.array_join(sf.collect_list('id_modality'), ",").alias('id_modality'),
        sf.array_join(sf.collect_list('zipcode_initial'), ",").alias('zipcode_initial'),
        sf.array_join(sf.collect_list('zipcode_final'), ",").alias('zipcode_final'),
        sf.array_join(sf.collect_list('cost'), ",").alias('cost'),
        sf.array_join(sf.collect_list('city'), ",").alias('city'),
        sf.array_join(sf.collect_list('state'), ",").alias('state')
    ).alias("infos_gerais_product")
))

# 验证schema
df_array.printSchema()

方式2:对现有DataFrame进行字段转换

如果已经生成了df_array,可以通过withColumn重新构造infos_gerais_product结构体,将每个数组字段转换为字符串:

from pyspark.sql import functions as sf

df2 = df_array.withColumn(
    "infos_gerais_product",
    sf.struct(
        sf.array_join(df_array.infos_gerais_product.id_distribution_center, ",").alias('id_distribution_center'),
        sf.array_join(df_array.infos_gerais_product.id_modality, ",").alias('id_modality'),
        sf.array_join(df_array.infos_gerais_product.zipcode_initial, ",").alias('zipcode_initial'),
        sf.array_join(df_array.infos_gerais_product.zipcode_final, ",").alias('zipcode_final'),
        sf.array_join(df_array.infos_gerais_product.cost, ",").alias('cost'),
        sf.array_join(df_array.infos_gerais_product.city, ",").alias('city'),
        sf.array_join(df_array.infos_gerais_product.state, ",").alias('state')
    )
)

# 验证schema
df2.printSchema()

注:如果需要其他分隔符,可以替换array_join的第二个参数(比如";");如果需要保留数组的原始格式(如带方括号),可以使用sf.to_json()代替array_join。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:35:20