如何从一系列地图创建数据集?

时间:2018-03-01 10:08:13

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

为什么以下失败?

val fd:Dataset[Map[Int, Int]] = Seq(Map(1->2, 3->4), Map(5->6), Map(8->9)).toDS()
    error: value toDS is not a member of Seq[scala.collection.immutable.Map[Int,Int]]

虽然这有效:

val cd:Dataset[Array[Int]] = Seq(Array(1, 2, 3), Array(100)).toDS()
    cd: org.apache.spark.sql.Dataset[Array[Int]] = [value: array<int>]

3 个答案:

答案 0 :(得分:4)

这是因为SQLImplicits Map编码器仅在Spark 2.3.0中添加。 升级到2.3.0并开始工作。

https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/SQLImplicits.scala#L170-L172

// Maps
/** @since 2.3.0 */
implicit def newMapEncoder[T <: Map[_, _] : TypeTag]: Encoder[T] = ExpressionEncoder()

答案 1 :(得分:3)

如果你可以升级到Spark 2.3 - 它可能是Traian建议的最好的主意。 Spark 2.0(在2.0.2上测试)可以使用变通方法:

1)将Map转换为Seq

scala> val seq2 = Seq(Map(1->2, 3->4), Map(5->6), Map(8->9)).map(_.toSeq)
seq2: Seq[Seq[(Int, Int)]] = List(ArrayBuffer((1,2), (3,4)), ArrayBuffer((5,6)), ArrayBuffer((8,9)))

scala> val ds = seq2.toDS()
ds: org.apache.spark.sql.Dataset[Seq[(Int, Int)]] = [value: array<struct<_1:int,_2:int>>]

scala> ds.printSchema()
root
 |-- value: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- _1: integer (nullable = false)
 |    |    |-- _2: integer (nullable = false)


scala> ds.collect().foreach(println)
WrappedArray((1,2), (3,4))
WrappedArray((5,6))
WrappedArray((8,9))

2)用案例类包装成struct(注意我必须在Spark 2.0的案例类定义中使用scala.collection.Map,因为另一个应该在2.1 / 2.2分支中修复的bug https://issues.apache.org/jira/browse/SPARK-18717

scala> case class WrapMap[K, V](m: scala.collection.Map[K, V])
defined class WrapMap

scala> val seq3 = Seq(Map(1->2, 3->4), Map(5->6), Map(8->9)).map(WrapMap(_))
seq3: Seq[WrapMap[Int,Int]] = List(WrapMap(Map(1 -> 2, 3 -> 4)), WrapMap(Map(5 -> 6)), WrapMap(Map(8 -> 9)))

scala> val ds = seq3.toDS()
ds: org.apache.spark.sql.Dataset[WrapMap[Int,Int]] = [m: map<int,int>]

scala> ds.collect().foreach(println)
WrapMap(Map(1 -> 2, 3 -> 4))
WrapMap(Map(5 -> 6))
WrapMap(Map(8 -> 9))

答案 2 :(得分:0)

您可以使用zipWithIndex,然后Map Dataset创建{。}}。

val fd: Dataset[Map[Int, Int]] =
    Seq(Map(1->2, 3->4), Map(5->6), Map(8->9)).zipWithIndex.toDS().map(_._1)