解决 Error:Unable to find encoder for type stored in a Dataset

Error: Unable to find encoder for type stored in a Dataset.  Primitive types (Int, String, etc) and Product types (case classes) are supported by importing spark.implicits._  Support for serializing other types will be added in future releases.

错误:无法找到存储在数据集中的类型的编码器。原始类型(Int,String等)和产品类型(case类)由导入spark.implicits支持。支持对其他类型的序列化,将在以后的版本中添加。


问题解决如下:

在开发过程中,我想将已经保存在HDFS上的文本文件保存成CSV格式的文件。

以前文件格式如下(这里使用自己造的假数据)每一列所对应的是 id,name,no,sp,ep
3303 龙顺 JD8 赤壁 湛江
5426 程凡 G58 龙岩 苗栗

我想处理成下面的格式,因为下面的格式是CSV默认格式
id,name,no,sp,ep
1309,项敬,BKZ,韶关,湖北
3507,宁风晨,KY7,河源,资阳

处理代码如下

def main(args: Array[String]) {
	val sparkSession = SparkSession.builder().appName("Spark shell").getOrCreate()
	//文件路径
	val path = "hdfs://master:9000/TestData/aviation9"
	//保存路径
	val savePath = "hdfs://master:9000/TestData/aviation10/"
	val file = sparkSession.read.textFile(path)
	//处理数据,拆分
	val rd = file.map(line => {
	  val arr = line.split("\t")
	  (arr(0), arr(1), arr(2), arr(3), arr(4))
	})
	//给DataFrame添加表头,
	val res = rd.toDF("id", "name", "no", "sp", "ep")
	//保存有表的文件
	res.repartition(1).write.mode(SaveMode.Append).format("csv").option("header", true).save(savePath)
}

准备打包运行,在打包的时候总是出现上面的错误

无法找到存储在数据集中的类型的编码器。
原始类型(Int,String等)和产品类型(case类)由导入spark.implicits支持。
支持对其他类型的序列化,将在以后的版本中添加。
所以需要我们自己在Dataset中添加元组这样的编码

解决办法:处理数据之间添加下面一行代码
implicit val matchError = org.apache.spark.sql.Encoders.tuple( Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING)


最后的全部代码是

def main(args: Array[String]) {
	val sparkSession = SparkSession.builder().appName("Spark shell").getOrCreate()
	//文件路径
	val path = "hdfs://master:9000/TestData/aviation9"
	//保存路径
	val savePath = "hdfs://master:9000/TestData/aviation10/"
	val file = sparkSession.read.textFile(path)
	implicit val matchError = org.apache.spark.sql.Encoders.tuple( Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING)
	//处理数据,拆分
	val rd = file.map(line => {
	  val arr = line.split("\t")
	  (arr(0), arr(1), arr(2), arr(3), arr(4))
	})
	//给DataFrame添加表头,
	val res = rd.toDF("id", "name", "no", "sp", "ep")
	//保存有表的文件
	res.repartition(1).write.mode(SaveMode.Append).format("csv").option("header", true).save(savePath)
}


在处理这个错误中,发现编码器中默认的tuple最多是5个元素,那如果我们有很多列数据该怎么处理呢?
比如现在的数据是下面这样的,多了一列time
5426 程凡 G56 2013-12-24 17:26:23 龙岩 苗栗
4413 相承 TV7 2014-04-09 20:44:25 北票 开原

如果在用下面的代码又出现同样的错误
implicit val matchError = org.apache.spark.sql.Encoders.tuple( Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING, Encoders.STRING)

因为在Encoders中最多支持5个元素的tuple,我们需要将DataSet转成处理成Row类型的,最后转成RDD用数据和表头创建一个DataFrame

def main(args: Array[String]) {
    val sparkSession = SparkSession.builder().appName("Spark shell").getOrCreate()
    val fields = "id,name,no,time,sp,ep"
    val path = "hdfs://master:9000/TestData/aviation9"
    val savePath = "hdfs://master:9000/TestData/aviation10/"
    
    val file: Dataset[String] = sparkSession.read.textFile(path)
    
    implicit val matchError = org.apache.spark.sql.Encoders.kryo[Row]
    //处理成Row
    val ds = file.map(x => {
      val arr = x.split("\t")
      Row.fromSeq(arr.toSeq)
    })
    //创建表头
    val field_array = fields.split(",")
    val schema = StructType(field_array.map(fieldName => StructField(fieldName, StringType, true)))
    //创建DataFrame
    val df = sparkSession.createDataFrame(ds.rdd, schema)
    df.repartition(1).write.mode(SaveMode.Append).format("csv").option("header", true).save(savePath)
}





猜你喜欢

转载自blog.csdn.net/zmc921/article/details/77051062