如何将SPARK SQL中的数据类型转换为特定数据类型,但将RDD结果转换为特定类

时间:2016-02-20 20:04:31

标签: scala apache-spark rdd

我正在阅读csv文件,需要创建一个RDDSchema
我使用sqlContext.csvFile

读取文件
val testfile = sqlContext.csvFile("file")
testfile.registerTempTable(testtable)

我想更改选择某些字段并返回这些字段的RDD类型 例如:class Test(ID:String,order_date:Date,Name:String,value:Double)

使用sqlContext.sql(“选择col1,col2,col3,col4 FROM ...)

 val testfile = sqlContext.sql("Select col1, col2, col3, col4 FROM testtable).collect
testfile.getClass
Class[_ <: Array[org.apache.spark.sql.Row]] = class [Lorg.apache.spark.sql.Row;

所以我想将col1更改为double,将col2更改为日期,将column3更改为string? 有没有办法在sqlContext.sql中执行此操作,或者我必须对结果运行map函数,然后将其转回RDD .. 我尝试在一个语句中执行该项目,我收到此错误:

 val old_rdd : RDD[Test] = sqlContext.sql("SELECT col, col2, col3,col4  FROM testtable").collect.map(t => (t(0) : String ,dateFormat.parse(dateFormat.format(1)),t(2) : String, t(3) : Double))

我遇到的问题是赋值不会导致RDD [Test],其中Test是一个定义的类

错误是map命令是作为Array Class而不是RDD Class

出现的
 found   : Array[edu.model.Test]
 [error]  required: org.apache.spark.rdd.RDD[edu.model.Test]

1 个答案:

答案 0 :(得分:0)

假设你有一个这样的案例类:

case class Test(
  ID: String, order_date: java.sql.Date, Name: String, value: Double)

由于您使用csvFile使用默认参数加载数据,因此它不执行任何架构推断,并且您的数据存储为纯字符串。让我们假设没有其他字段:

val df = sc.parallelize(
  ("ORD1", "2016-01-02", "foo", "2.23") ::
  ("ORD2", "2016-07-03", "bar", "9.99") :: Nil
).toDF("col1", "col2", "col3", "col4")

由于多种原因,您尝试使用地图是错误的:

  • 您使用的函数用不正确的类型注释单个值。 Row.apply不仅属于Int => Any类型,而且您的数据表中不包含任何Double
  • ,因为您collect(这里没有意义)您将所有数据提取到驱动程序,结果是本地Array而非RDD
  • 最后,如果以前的所有问题都已解决,(String, Date, String, Double)显然不是Test

处理此问题的一种方法:

import org.apache.spark.sql.Row
import org.apache.spark.rdd.RDD

val casted = df.select(
  $"col1".alias("ID"),
  $"col2".cast("date").alias("order_date"),
  $"col3".alias("name"),
  $"col4".cast("double").alias("value")
)

val tests: RDD[Test] = casted.map {
  case Row(id: String, date: java.sql.Date, name: String, value: Double) =>
    Test(id, date, name, value)
}

您也可以尝试使用新的Dataset API,但它远非稳定:

casted.as[Test].rdd