在运行spark应用程序时,我在催化剂深处发现错误。
例如:
java.lang.RuntimeException: scala.MatchError: LongType (of class org.apache.spark.sql.types.LongType$)
org.apache.spark.sql.catalyst.expressions.Cast.org$apache$spark$sql$catalyst$expressions$Cast$$nullSafeCastFunction(Cast.scala:637)
org.apache.spark.sql.catalyst.expressions.Cast.doGenCode(Cast.scala:625)
org.apache.spark.sql.catalyst.expressions.Expression$$anonfun$genCode$2.apply(Expression.scala:107)
org.apache.spark.sql.catalyst.expressions.Expression$$anonfun$genCode$2.apply(Expression.scala:104)
scala.Option.getOrElse(Option.scala:121)
org.apache.spark.sql.catalyst.expressions.Expression.genCode(Expression.scala:104)
在火花计划中,我将范围缩小到以下范围:
Project [if (isnull(_rawTime#348L)) null else UDF(toTime(_rawTime#348L)) AS _time#438,
(请注意,我无法控制架构为null,因为我是从spark hbase连接器获取此基础数据框的。)
toTime
是一个UDF,它花费很长的时间并生成时间戳。即使match语句具有:
LongType
case LongType => castToLongCode(from, ctx)
有趣的是,当我第一次运行此程序时,它运行良好。在第二次运行时,它存在此问题。
请注意,这是通过apache Livy运行的,因此执行之间的基本Spark会话应该相同。
我在工作开始时放置了以下代码。
logger.info("----------")
logger.info(LongType + " " + System.identityHashCode(LongType))
logger.info(DataTypes.LongType + " " + System.identityHashCode(DataTypes.LongType))
logger.info("Equal " + (DataTypes.LongType == LongType))
logger.info("----------")
然后运行它,我看到:
first run:
----------
LongType 1044985410
LongType 1044985410
Equal true
----------
second run:
----------
LongType 355475697
LongType 1044985410
Equal false
----------
您可以看到在运行2中,对LongType的基于对象的调用与第一次运行时的标识不同。
Spark的注释建议人们使用DataTypes中的单例。例如{。{1}},因为看起来它们保持不变。但是,spark的代码使用非单例代码。
LongType定义为
DataTypes.LongType
/**
* @since 1.3.0
*/
@InterfaceStability.Stable
case object LongType extends LongType
是
DataTypes.LongType
哪个引用前者(案例对象)。单例保持不变是有道理的。实际上,尽管内部火花代码的加载并未执行此操作,但是火花代码仍显示public static final DataType LongType = LongType$.MODULE$;
DataTypes.LongType Please use the singleton
..。对我来说,这就像个虫子。
Spark中的Scala代码可以正常编译,然后由于类型上的这种突然的标识更改而失败,这似乎很奇怪。
所以我的问题是:
.
的建议是什么?我应该使用单例还是非单例? 答案 0 :(得分:0)
我已经解决了这个问题。
基本上所有的DataType实例在Scala中都定义为:
* @since 1.3.0
*/
@InterfaceStability.Stable
case object LongType extends LongType
但是...在许多地方,Spark使用Java代码通过单例获取DataType:
* Gets the LongType object.
*/
public static final DataType LongType = LongType$.MODULE$;
LongType$.MODULE$;
是如何从java领域调用案例对象。
但是我正在使用Kryo将DataType
序列化为Livy,而Kryo正在内部重新初始化LongType$.MODULE$;
。在Scala中,获得案例Object时获得的引用不是绑定到创建的第一个实例,而是绑定到创建的 last 实例。
因此时间表是:
DataTypes.LongType
的参考为1,LongType
的参考为
1也。 (其中ref
仅表示参考)DataTypes.LongType
的参考值为1,LongType
的参考值为2
解决方案是不以这种方式将case对象传递给Kryo。可能由于某些原因,我们没有正确使用Kryo,或者我们需要使用twitter / chill。