相反,将DataFrame提取到Case类中会导致读取Tuple1

时间:2019-01-21 20:17:03

标签: scala apache-spark

给出一个case class

case class ScoringSummary(MatchMethod: String="", 
TP: Double=0, 
FP: Double=0, 
Precision: Double=0, 
Recall: Double=0, 
F1: Double=0)

我们将摘要记录写为:

summaryDf.write.parquet(path)

稍后(我们打算)将镶木地板文件读取到新的数据框中:

implicit val generalRowEncoder: Encoder[ScoringSummary] = 
    org.apache.spark.sql.Encoders.kryo[ScoringSummary]
val summaryDf = spark.read.parquet(path).as[ScoringSummary]

但是失败了-由于某种原因,spark认为数据的内容是Tuple1而不是ScoringSummary

Try to map struct<MatchMethod:string,TP:double,FP:double,Precision:double,
Recall:double,F1:double> to Tuple1, 
but failed as the number of fields does not line up.;
    at org.apache.spark.sql.catalyst.analysis.Analyzer$ResolveDeserializer$
.org$apache$spark$sql$catalyst$analysis$Analyzer$
ResolveDeserializer$$fail(Analyzer.scala:2168)

缺少什么步骤/设置/翻译不正确?

1 个答案:

答案 0 :(得分:2)

使用import spark.implicits._代替注册编码器

我忘记了导入spark.implicits是必需的。错误的方法是添加Encoder:即 包括以下行

implicit val generalRowEncoder: Encoder[ScoringSummary] = 
org.apache.spark.sql.Encoders.kryo[ScoringSummary]   // Do NOT add this Encoder

这是删除Encoder行时的错误

  

错误:(59,113)无法找到存储在数据集中的类型的编码器。   基本类型(Int,String等)和产品类型(案例类)   通过导入spark.implicits._得到支持   其他类型将在将来的版本中添加。       val summaryDf = ParquetLoader.loadParquet(sparkEnv,res.state.dfs(ScoringSummaryTag).copy(df = None))。df.get.as [ScoringSummary]

相反,应添加以下代码

import spark.implicits._

然后相同的代码起作用:

val summaryDf = spark.read.parquet(path).as[ScoringSummary]

enter image description here

顺便说一句:case classprimitive类型不需要编码器:而上述 是{{1} }。 case class对于复杂的对象类型很方便。