UnresolvedException:使用从Seq.empty构造的DataSet时对未解析对象的dataType调用无效(自Spark 2.3.0起)

时间:2018-04-10 15:25:12

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

以下代码段在Spark 2.2.1中运行正常,但在Spark 2.3.0中给出了一个相当神秘的运行时异常:

import sparkSession.implicits._
import org.apache.spark.sql.functions._

case class X(xid: Long, yid: Int)
case class Y(yid: Int, zid: Long)
case class Z(zid: Long, b: Boolean)

val xs = Seq(X(1L, 10)).toDS()
val ys = Seq(Y(10, 100L)).toDS()
val zs = Seq.empty[Z].toDS()

val j = xs
  .join(ys, "yid")
  .join(zs, Seq("zid"), "left")
  .withColumn("BAM", when('b, "B").otherwise("NB"))

j.show()

在Spark 2.2.1中,它会打印到控制台

+---+---+---+----+---+
|zid|yid|xid|   b|BAM|
+---+---+---+----+---+
|100| 10|  1|null| NB|
+---+---+---+----+---+

在Spark 2.3.0中,结果为:

org.apache.spark.sql.catalyst.analysis.UnresolvedException: Invalid call to dataType on unresolved object, tree: 'BAM
  at org.apache.spark.sql.catalyst.analysis.UnresolvedAttribute.dataType(unresolved.scala:105)
  at org.apache.spark.sql.types.StructType$$anonfun$fromAttributes$1.apply(StructType.scala:435)
  at org.apache.spark.sql.types.StructType$$anonfun$fromAttributes$1.apply(StructType.scala:435)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
  at scala.collection.immutable.List.foreach(List.scala:392)
  at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
  at scala.collection.immutable.List.map(List.scala:296)
  at org.apache.spark.sql.types.StructType$.fromAttributes(StructType.scala:435)
  at org.apache.spark.sql.catalyst.plans.QueryPlan.schema$lzycompute(QueryPlan.scala:157)
  ...

真正的罪魁祸首似乎是从空Dataset创建的Seq[Z]。当你将它改为一个也会导致空Dataset[Z]的东西时,它就像在Spark 2.2.1中那样工作,例如

val zs = Seq(Z(10L, true)).toDS().filter('zid === 999L)

在2.2到2.3的迁移指南中提到:

  

从Spark 2.3开始,如果可能的话,在第一个非确定性谓词之后的Join / Filter的确定性谓词也会向下推/通过子运算符。在以前的Spark版本中,这些过滤器不适用于谓词下推。

这是相关的还是(已知的)错误?

2 个答案:

答案 0 :(得分:2)

@ user9613318有一个bug create by the OP,但它被关闭为“无法重现”,因为开发人员说

  

我无法在当前主人身上重现。这一定必须修复。

但没有提及另一个潜在的问题,所以它可能仍然是一个谜。

答案 1 :(得分:1)

我在2.3.0上通过在创建空someEmptyDataset.cache()之后立即发出Dataset解决了这一问题。 OP的示例再也不会失败(使用zs.cache()),使用该技巧也可以解决实际的工作问题。

(作为一个附带说明,在本地运行的Spark 2.3.2上,OP-s代码不会对我失败。尽管我在2.3.2更改日志中未看到相关的修复程序,所以可能是由于其他原因环境的差异...)