【问题标题】:Can I change the nullability of a column in my Spark dataframe?我可以更改 Spark 数据框中列的可空性吗?
【发布时间】:2017-09-06 10:06:27
【问题描述】:

我在数据框中有一个不可为空的 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

返回:

[StructField(name,StringType,true), StructField(年龄,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)

失败了:

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

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

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

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

【问题讨论】:

    标签: python pyspark apache-spark-sql


    【解决方案1】:

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

    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
    

    你可以这样称呼它:

    set_df_columns_nullable(spark,df,['name','age'])
    

    【讨论】:

    • 很好的答案。这样做有什么性能影响吗?当你基于现有的 RDD “创建一个新的数据框”时,究竟会发生什么?
    【解决方案2】:

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

    df.schema['col_1']
    # StructField(col_1,DoubleType,false)
    
    df.schema['col_1'].nullable = True
    
    df.schema['col_1']
    # StructField(col_1,DoubleType,true)
    

    【讨论】:

      【解决方案3】:

      您似乎错过了 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()
      

      【讨论】:

        【解决方案4】:
        df1 = df.rdd.toDF()
        df1.printSchema()
        

        输出:

        root
         |-- name: string (nullable = true)
         |-- age: long (nullable = true)
         |-- foo: boolean (nullable = true)
        

        【讨论】:

          猜你喜欢
          • 2017-02-05
          • 1970-01-01
          • 2016-01-16
          • 2018-02-28
          • 1970-01-01
          • 2018-10-15
          • 2020-07-26
          • 2021-09-01
          • 1970-01-01
          相关资源
          最近更新 更多