我正在尝试运行这个小型Spark程序。 Spark Version 2.1.1
val rdd = sc.parallelize(List((2012, "Tesla", "S"), (1997, "Ford", "E350"), (2015, "Chevy", "Volt")))
import spark.implicits._
val carDetails: Dataset[CarDetails] = spark.createDataset(rdd).as[CarDetails] // Error Line
carDetails.map(car => {
val name = if (car.name == "Tesla") "S" else car.name
CarDetails(car.year, name, car.model)
}).collect().foreach(print)
在这一行上抛出错误:
val carDetails: Dataset[CarDetails] = spark.createDataset(rdd).as[CarDetails]
Exception in thread "main" org.apache.spark.sql.AnalysisException: cannot resolve '`year`' given input columns: [_1, _2, _3];
没有编译错误!
我试过做很多改动,比如使用List而不是RDD。此外,尝试先转换为DS,然后转换为as[CarDetails]
,但无法正常工作。现在我一无所知。
为什么在我已经给出案例类
时将列作为_1
,_2
和_3
?
case class CarDetails(year: Int, name: String, model: String)
我尝试在案例课程中从Int更改为Long。它仍然无效。
修改
我在提到可能的重复问题之后改变了这一行,并且它有效。
val carDetails: Dataset[CarDetails] = spark.createDataset(rdd)
.withColumnRenamed("_1","year")
.withColumnRenamed("_2","name")
.withColumnRenamed("_3","model")
.as[CarDetails]
但是,即使在显式映射到案例类之后,我仍然不清楚为什么我需要重命名列。
答案 0 :(得分:1)
as
Tuple*
转换的规则
用于映射列的方法取决于U的类型:
- 当U是一个类时,该类的字段将映射到同名的列(区分大小写由spark.sql.caseSensitive决定)。
- 当U是元组时,列将按顺序映射(即第一列将分配给_1)。
- 当U是基本类型(即String,Int等)时,将使用DataFrame的第一列。
如果数据集的架构与所需的U类型不匹配,您可以使用select with alias或者根据需要重新排列或重命名。
用代码解释这个。从案例类到Seq(CarDetails(2012, "Tesla", "S")).toDF.as[(Int, String, String)]
的转换有效(字段在结构上匹配):
Tuple*
但是从Seq((2012, "Tesla", "S")).toDF("year", "name", "model").as[CarDetails]
到任意案例类的转换不是(字段按名称匹配)。您必须先重命名字段(同上):
Tuple
它具有非常有趣的实际意义:
case class CarDetailsWithColor(
year: Int, name: String, model: String, color: String)
Seq(
CarDetailsWithColor(2012, "Tesla", "S", "red")
).toDF.as[(Int, String, String)]
// org.apache.spark.sql.AnalysisException: Try to map struct<year:int,name:string,model:string,color:string> to Tuple3, but failed as the number of fields does not line up.;
类型对象不能包含无关字段:
Dataset
虽然案例类型Seq(
(2012, "Tesla", "S", "red")
).toDF("year", "name", "model", "color").as[CarDetails]
可以:
sc.parallelize(Seq(CarDetails(2012, "Tesla", "S"))).toDS
当然,从case class typed variant开始可以省去所有麻烦:
{{1}}