Quirk with accessing struct attributes - can access attributes by their index, not their names

Viewed 136

After adding a column (an array of structs) to a dataframe, I wanted to run a UDF on this added column. Now, I cannot access the attributes of the structs through their names, but I can access them with their index.

However, if I cache the dataframe, then accessing by attribute names starts working.

Here's the reproducible code:

import pyspark.sql.functions as spf
import pyspark.sql.types as spt

df = spark.createDataFrame([{"something": 1}])
tuple_schema = spt.ArrayType(
    elementType=spt.StructType([spt.StructField("x", spt.FloatType()),
                                spt.StructField("y", spt.FloatType())]))

def generate_tuples():
    return [(3.0, 4.0)]

tuple_udf = spf.udf(generate_tuples, tuple_schema)
df = df.withColumn("our_tuples", tuple_udf())
df.collect()
# [Row(something=1, our_tuples=[Row(x=3.0, y=4.0)])]

index_udf = spf.udf(lambda lst: max([z[1] for z in lst]) \
    if len(lst) > 0 else 0.0, spt.FloatType())
attribute_udf = spf.udf(lambda lst: max([z.y for z in lst]) \
    if len(lst) > 0 else 0.0, spt.FloatType())

This works: ✔️

index_df = df.withColumn("m", index_udf(df.our_tuples))
index_df.collect()

This doesn't work: ❌

attribute_df = df.withColumn("m", attribute_udf(df.our_tuples))
attribute_df.collect()
# AttributeError: 'tuple' object has no attribute 'y'

This again works: ✔️

df.cache()
df.count()
attribute_df = df.withColumn("m", attribute_udf(df.our_tuples))
attribute_df.collect()

Is this a Spark bug, or an expected behaviour I'm unaware of?

0 Answers
Related