我可以更改 Spark 数据框中列的可空性吗?

jam*_*iet 6 python apache-spark-sql pyspark

我在不可为空的数据框中有一个 StructField。简单的例子:

import pyspark.sql.functions as F
from pyspark.sql.types import *
l = [('Alice', 1)]
df = sqlContext.createDataFrame(l, ['name', 'age'])
df = df.withColumn('foo', F.when(df['name'].isNull(),False).otherwise(True))
df.schema.fields
Run Code Online (Sandbox Code Playgroud)

返回:

[StructField(name,StringType,true), StructField(age,LongType,true), StructField(foo,BooleanType,false)]

请注意,该字段foo不可为空。问题是(出于我不会讨论的原因)我希望它可以为空。我发现这篇文章Change nullable property of column in spark dataframe建议了一种方法,所以我将其中的代码调整为:

import pyspark.sql.functions as F
from pyspark.sql.types import *
l = [('Alice', 1)]
df = sqlContext.createDataFrame(l, ['name', 'age'])
df = df.withColumn('foo', F.when(df['name'].isNull(),False).otherwise(True))
df.schema.fields
newSchema = [StructField('name',StringType(),True), StructField('age',LongType(),True),StructField('foo',BooleanType(),False)]
df2 = sqlContext.createDataFrame(df.rdd, newSchema)
Run Code Online (Sandbox Code Playgroud)

失败了:

TypeError: StructField(name,StringType,true) 不是 JSON 可序列化的

我也在堆栈跟踪中看到了这一点:

raise ValueError("检测到循环引用")

所以我有点卡住了。任何人都可以修改这个例子,使我能够定义一个列可以foo为空的数据框吗?

ica*_*rus 10

我知道这个问题已经得到解答,但是当我想出这个问题时,我正在寻找一个更通用的解决方案:

def set_df_columns_nullable(spark, df, column_list, nullable=True):
    for struct_field in df.schema:
        if struct_field.name in column_list:
            struct_field.nullable = nullable
    df_mod = spark.createDataFrame(df.rdd, df.schema)
    return df_mod
Run Code Online (Sandbox Code Playgroud)

然后你可以这样称呼它:

set_df_columns_nullable(spark,df,['name','age'])
Run Code Online (Sandbox Code Playgroud)

  • @malthe 和其他人来到这里,似乎这非常昂贵,我仅使用 10X1 df 对其进行了测试,而没有更新可空值的测试花费了“184.47592 毫秒”,而更新可空值则花费了“1187.75746 毫秒” (5认同)

小智 5

似乎您错过了 StructType(newSchema)。

l = [('Alice', 1)]
df = sqlContext.createDataFrame(l, ['name', 'age'])
df = df.withColumn('foo', F.when(df['name'].isNull(),False).otherwise(True))
df.schema.fields
newSchema = [StructField('name',StringType(),True), StructField('age',LongType(),True),StructField('foo',BooleanType(),False)]
df2 = sqlContext.createDataFrame(df.rdd, StructType(newSchema))
df2.show()
Run Code Online (Sandbox Code Playgroud)


yat*_*atu 5

对于一般情况,可以通过特定列的nullable属性更改列的可空性StructField。下面是一个例子:

df.schema['col_1']
# StructField(col_1,DoubleType,false)

df.schema['col_1'].nullable = True

df.schema['col_1']
# StructField(col_1,DoubleType,true)
Run Code Online (Sandbox Code Playgroud)

  • 这似乎只有在我使用架构更改重新创建数据框时才有效。有没有办法做到这一点“在线”? (2认同)