我需要转换镶木地板文件的内部结构。
目前我有一个存储数组或数组的字段。我打算把它变成一个结构数组。
所以从这个:
root
-array
-array
我想得到这个:
root
-array
-struct
我正在按以下方式执行转换:
我为新结构定义了一个模式:
newtype = ArrayType(StructType(
[
StructField("one", FloatType()),
StructField("two", FloatType()),
StructField("three", FloatType()),
StructField("four", FloatType()),
StructField("five", FloatType())
]))
我将'空'udf应用于列。有趣的是我指定了udf的模式。
def convert(arr):
return arr
df = spark.read.parquet("....")
spark.udf.register(name="convert", f=convert, returnType=newtype)
df = df.withColumn("col", expr("convert(col)"))
最后我把它写回实木复合地板。
我得到的问题是:
输入行没有预期的值所需的值 架构。需要5个字段,同时提供3个值。
确实如此。一些阵列曾经有3个值。稍后会添加更多值,因此较新的数组有5个值。
为什么会发生这种情况?我将这些字段定义为可以为空,所以我希望这可以工作。 我的选择是什么?
答案 0 :(得分:3)
将数据转换为新的结构模式时,必须为每个字段提供一个值。如果你不提供它们,Spark并不想假设要放入什么值。如果长度错误,只需为剩余值提供None。你的转换函数看起来也不像处理嵌套数组。这是一个工作示例,其中convert已更新为pad with pad' s。
from pyspark.sql.types import *
from pyspark.sql.functions import *
old_type = StructType([
StructField("col", ArrayType(ArrayType(FloatType())))
])
new_type = ArrayType(StructType([
StructField("one", FloatType()),
StructField("two", FloatType()),
StructField("three", FloatType()),
StructField("four", FloatType()),
StructField("five", FloatType())
]))
data = [
([[1., 2., 3.], [1., 2., 3., 4., 5.]],)
]
rdd = spark.sparkContext.parallelize(data)
df = sqlContext.createDataFrame(rdd, old_type)
def convert(arr):
vals = []
for v in arr:
padding = [None] * (5 - len(v))
vals.append(v + padding)
return vals
spark.udf.register(name="convert", f=convert, returnType=new_type)
df = df.withColumn("col", expr("convert(col)"))
df.show(10, False)