Spark DataFrame列名未传递给从节点?

时间:2015-12-24 18:26:57

标签: scala apache-spark dataframe apache-spark-sql rdd

我正在应用一个函数,让我们说f(),通过map方法到DataFrame的行(称之为df)但是如果{{1} {}我在调用生成RDD上的collect时看到NullPointerException }作为参数传递给f()。

以下Scala代码(可以粘贴在spark-shell中)显示了该问题的最小示例(请参阅函数df.columns)。我还在函数prepRDD_buggy()中发布了此问题的当前解决方法,其中列名称作为prepRDD()而不是val传递的唯一区别。

请问一些Spark专家请指出发生这种情况的确切原因或确认我们的假设,即从属节点没有得到DataFrame列名?

df.columns

以下是我在spark-shell中运行import org.apache.spark.SparkContext import org.apache.spark.sql.{DataFrame, Row} import org.apache.spark.sql.types._ import org.apache.spark.rdd.RDD import org.apache.spark.mllib.regression.LabeledPoint import org.apache.spark.mllib.linalg.Vectors // A Simple DataFrame val dataRDD: RDD[Row] = sc.parallelize(Array( Row(1.0,2.1,3.3), Row(3.4,5.9,8.9), Row(3.1,2.3,4.1))) val struct: StructType = StructType( StructField("y", DoubleType, false) :: StructField("x1", DoubleType, false) :: StructField("x2", DoubleType, false) :: Nil) val df: DataFrame = sqlContext.createDataFrame(dataRDD, struct) // Make LabeledPoint object from Row objects def makeLP(row: Row, colnames: Array[String]) = LabeledPoint(row.getDouble(0), Vectors.dense((1 until row.length).toArray map (i => row.getDouble(i)))) // Make RDD[LabeledPoint] from DataFrame def prepRDD_buggy(df: DataFrame): RDD[LabeledPoint] = { df map (row => makeLP(row, df.columns)) } val mat_buggy = prepRDD_buggy(df) mat_buggy.collect // throws NullPointerException ! // Make RDD[LabeledPoint] from DataFrame def prepRDD(df: DataFrame): RDD[LabeledPoint] = { val cnames = df.columns df map (row => makeLP(row, cnames)) } val mat = prepRDD(df) mat.collect // Works fine 时看到的(非常详细)错误消息的前几行。

mat_buggy.collect

1 个答案:

答案 0 :(得分:4)

您的假设是正确的。 columns需要访问schema,并且架构取决于queryExecution,这是暂时性的,因此无法运送给工作人员。因此,您在prepRDD中所做的事情或多或少是正确的,尽管可以直接从行中提取相同的信息:

scala> df.rdd.map(_.schema.fieldNames).first
res14: Array[String] = Array(y, x1, x2, x3)

旁注VectorAssembler加简单map将是更好的选择。