为什么在Apache Spark SQL中列会变成可空?

11
为什么在DataFrame中不存在NaN值的情况下,有些函数执行后会使用nullable = true ?
val myDf = Seq((2,"A"),(2,"B"),(1,"C"))
         .toDF("foo","bar")
         .withColumn("foo", 'foo.cast("Int"))

myDf.withColumn("foo_2", when($"foo" === 2 , 1).otherwise(0)).select("foo", "foo_2").show

当现在调用df.printSchema时,nullable对于两个列都将是false

val foo: (Int => String) = (t: Int) => {
    fooMap.get(t) match {
      case Some(tt) => tt
      case None => "notFound"
    }
  }

val fooMap = Map(
    1 -> "small",
    2 -> "big"
 )
val fooUDF = udf(foo)

myDf
    .withColumn("foo", fooUDF(col("foo")))
    .withColumn("foo_2", when($"foo" === 2 , 1).otherwise(0)).select("foo", "foo_2")
    .select("foo", "foo_2")
    .printSchema

然而现在,至少有一列的nullable属性从之前的false变为了true。这是如何解释的?
2个回答

14

创建Dataset时,如果从静态类型结构(不依赖于schema参数)创建,则Spark使用一组相对简单的规则来确定nullable属性。

  • 如果给定类型的对象可以是null,则其DataFrame表示形式为nullable
  • 如果对象是Option[_],则其DataFrame表示形式为可nullable,其中None被视为SQL NULL
  • 在任何其他情况下,它将被标记为不可nullable

由于Scala Stringjava.lang.String,因此它可以是null,生成的列可以是nullable。出于同样的原因,在初始数据集中bar列也是可nullable的:

val data1 = Seq[(Int, String)]((2, "A"), (2, "B"), (1, "C"))
val df1 = data1.toDF("foo", "bar")
df1.schema("bar").nullable
Boolean = true

但是foo不是scala.Intnull不能是scala.Int)。

df1.schema("foo").nullable
Boolean = false

如果我们将数据定义更改为:

val data2 = Seq[(Integer, String)]((2, "A"), (2, "B"), (1, "C"))

foo将是nullableIntegerjava.lang.Integer,装箱整数可以为null):

data2.toDF("foo", "bar").schema("foo").nullable
Boolean = true

另请参阅:SPARK-20668 修改ScalaUDF以处理可空性


我看过的关于这个话题最好的答案。 - sparkyShorts

3
您可以非常快速地更改数据帧的模式。像这样的东西可以完成工作 -
def setNullableStateForAllColumns( df: DataFrame, columnMap: Map[String, Boolean]) : DataFrame = {
    import org.apache.spark.sql.types.{StructField, StructType}
    // get schema
    val schema = df.schema
    val newSchema = StructType(schema.map {
    case StructField( c, d, n, m) =>
      StructField( c, d, columnMap.getOrElse(c, default = n), m)
    })
    // apply new schema
    df.sqlContext.createDataFrame( df.rdd, newSchema )
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接