从行中读取列时出现NullPointerException

时间:2017-12-19 08:14:37

标签: scala apache-spark spark-dataframe apache-spark-1.6

当值为null时,以下用于从行读取值的Scala(Spark 1.6)代码失败,并显示NullPointerException

val test = row.getAs[Int]("ColumnName").toString

虽然这很好用

val test1 = row.getAs[Int]("ColumnName") // returns 0 for null
val test2 = test1.toString // converts to String fine

导致NullPointerException的原因是什么,以及处理此类案件的推荐方法是什么?

PS:从DataFrame获取行如下:

val myRDD = myDF.repartition(partitions)
  .mapPartitions{ rows => 
    rows.flatMap{ row =>
      functionWithRows(row) //has above logic to read null column which fails
    }
  }

functionWithRows上面提到了NullPointerException

MyDF架构:

root
 |-- LDID: string (nullable = true)
 |-- KTAG: string (nullable = true)
 |-- ColumnName: integer (nullable = true)

2 个答案:

答案 0 :(得分:1)

getAs定义为:

def getAs[T](i: Int): T = get(i).asInstanceOf[T]

当我们执行toString时,我们调用Object.toString并不依赖于类型,因此编译器会删除asInstanceOf[T],即

row.getAs[Int](0).toString -> row.get(0).toString

我们可以通过编写一个简单的scala代码来确认:

import org.apache.spark.sql._

object Test {
  val row = Row(null)
  row.getAs[Int](0).toString
}

然后编译它:

$ scalac -classpath $SPARK_HOME/jars/'*' -print test.scala
[[syntax trees at end of                   cleanup]] // test.scala
package <empty> {
  object Test extends Object {
    private[this] val row: org.apache.spark.sql.Row = _;
    <stable> <accessor> def row(): org.apache.spark.sql.Row = Test.this.row;
    def <init>(): Test.type = {
      Test.super.<init>();
      Test.this.row = org.apache.spark.sql.Row.apply(scala.this.Predef.genericWrapArray(Array[Object]{null}));
      Test.this.row().getAs(0).toString();
      ()
    }
  }
}

所以正确的方法是:

String.valueOf(row.getAs[Int](0))

答案 1 :(得分:0)

为了避免空值,最好在检查之前使用isNullAt,因为documentation建议:

  

<强> getAs

     

<T> T getAs(int i)

     

返回位置i的值。对于原始类型,如果value为null,则为null   返回零值&#39;特定的原始即。 0的{​​{1}} - 使用Int确保该值不为空

我同意这种行为令人困惑。