spark数据框中的空值

时间:2017-05-08 22:16:48

标签: scala apache-spark

我正在尝试将数据框插入cassandra:

result.rdd.saveToCassandra(keyspaceName, tableName)

但是有些列值为空,因此我得到例外:

java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
at java.lang.Float.parseFloat(Float.java:451)
at scala.collection.immutable.StringLike$class.toFloat(StringLike.scala:231)
at scala.collection.immutable.StringOps.toFloat(StringOps.scala:31)
at com.datastax.spark.connector.types.TypeConverter$FloatConverter$$anonfun$convertPF$4.applyOrElse(TypeConverter.scala:216)

有没有办法在数据框中用null替换所有EMPTY值,这会解决这个问题吗? 对于这个问题,我们假设这是数据帧df:

col1 | col2 | col3
"A"  | "B"  | 1
"E"  | "F"  | 
"S"  | "K"  | 5

如何将col3中的空值替换为null?

3 个答案:

答案 0 :(得分:0)

您可以为此写一个udf

val df = Seq(("A", "B", "1"), ("E", "F", ""), ("S", "K", "1")).toDF("col1", "col2", "col3")
// make a udf that converts String to option[String]
val nullif = udf((s: String) => if(s == "") None else Some(s))

df.withColumn("col3", nullif($"col3")).show

+----+----+----+
|col1|col2|col3|
+----+----+----+
|   A|   B|   1|
|   E|   F|null|
|   S|   K|   1|
+----+----+----+

如果您想避免使用 udf ,也可以使用when.otherwise

df.withColumn("col3", when($"col3" === "", null).otherwise($"col3")).show

+----+----+----+
|col1|col2|col3|
+----+----+----+
|   A|   B|   1|
|   E|   F|null|
|   S|   K|   1|
+----+----+----+

或者您可以使用SQL nullif函数将空字符串转换为null:

df.selectExpr("col1", "col2", "nullif(col3, \"\") as col3").show
+----+----+----+
|col1|col2|col3|
+----+----+----+
|   A|   B|   1|
|   E|   F|null|
|   S|   K|   1|   
+----+----+----+

答案 1 :(得分:0)

如果您将DataFrame列转换为数字类型,那么任何无法削减到相应类型的值都将变为空值。

import org.apache.spark.sql.types.IntegerType
df.select(
   $"col1",
   $"col2",
   $"col3" cast IntegerType
)

或者如果您没有选择陈述

 df.withColumn("col3", df("col3") cast IntegerType)

如果你有很多列想要应用它,并且觉得在select语句中执行此操作太不方便或者如果转换不适合你的情况,你可以转换为rdd来应用转换然后返回到数据帧。您可能想要为此定义一种方法。

  def emptyToNull(df: DataFrame): DataFrame = {
    val sqlCtx = df.sqlContext
    val schema = df.schema

    val rdd = df.rdd.map(
      row =>
        row.toSeq.map {
          case "" => null
          case otherwise => otherwise
        })
      .map(Row.fromSeq)

    sqlCtx.createDataFrame(rdd, schema)
  }

答案 2 :(得分:0)

使用前:

=SUMIF(C4:C13,">0",C2:C11)

使用演员表:

//将RDD映射到rowRDD
val rowRDD = personRDD.map(p => Row(p(0).trim.toLong, p(1).trim, p(2).trim, p(3).trim.toLong, p(4).trim.toLong))

使用方法:

//通过StructType直接指定每个字段的schema
val schema = StructType(
  StructField("id", LongType, false) ::
    StructField("name", StringType, true) ::
    StructField("gender", StringType, true) ::
    StructField("salary", LongType, true) ::
    StructField("expense", LongType, true) :: Nil
)

//允许字段为空
val rdd = personRDD.map(row =>
  row.toSeq.map(r => {
    if (r.trim.length > 0) {
      val castValue = Util.castTo(r.trim, schema.fields(row.toSeq.indexOf(r)).dataType)
      castValue
    }
    else null
  })).map(Row.fromSeq)