为什么Spark / Scala编译器无法在RDD [Map [Int,Int]]上找到toDF?

时间:2015-09-11 11:56:02

标签: scala apache-spark apache-spark-sql

为什么以下结果会出错?

scala> import sqlContext.implicits._
import sqlContext.implicits._

scala> val rdd = sc.parallelize(1 to 10).map(x => (Map(x  -> 0), 0))
rdd: org.apache.spark.rdd.RDD[(scala.collection.immutable.Map[Int,Int], Int)] = MapPartitionsRDD[20] at map at <console>:27

scala> rdd.toDF
res8: org.apache.spark.sql.DataFrame = [_1: map<int,int>, _2: int]

scala> val rdd = sc.parallelize(1 to 10).map(x => Map(x  -> 0))
rdd: org.apache.spark.rdd.RDD[scala.collection.immutable.Map[Int,Int]] = MapPartitionsRDD[23] at map at <console>:27

scala> rdd.toDF
<console>:30: error: value toDF is not a member of org.apache.spark.rdd.RDD[scala.collection.immutable.Map[Int,Int]]
              rdd.toDF

那么到底发生了什么,toDF可以将(scala.collection.immutable.Map[Int,Int], Int)类型的RDD转换为DataFrame,而不是类型scala.collection.immutable.Map[Int,Int]。这是为什么?

2 个答案:

答案 0 :(得分:9)

出于同样的原因,你不能使用

sqlContext.createDataFrame(1 to 10).map(x => Map(x  -> 0))

如果您查看org.apache.spark.sql.SQLContext来源,您会发现createDataFrame方法的两种不同实现:

def createDataFrame[A <: Product : TypeTag](rdd: RDD[A]): DataFrame  

def createDataFrame[A <: Product : TypeTag](data: Seq[A]): DataFrame 

正如您所看到的,两者都需要A作为Product的子类。当您在toDF上致电RDD[(Map[Int,Int], Int)]时,Tuple2确实是ProductMap[Int,Int]本身并不是错误。

您可以使用Map

包装Tuple1来使其有效
sc.parallelize(1 to 10).map(x => Tuple1(Map(x  -> 0))).toDF

答案 1 :(得分:5)

基本上是因为没有隐式为RDD内的Map创建DataFrame。

在第一个示例中,您将返回一个Tuple,它是一个隐式转换的Product。

rddToDataFrameHolder[A <: Product : TypeTag](rdd: RDD[A])

在第二个示例中,您使用的RDD中有一个Map,没有隐式转换。