给出一个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)
缺少什么步骤/设置/翻译不正确?
答案 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]
顺便说一句:case class
或primitive
类型不需要编码器:而上述 是{{1} }。 case class
对于复杂的对象类型很方便。