Spark - 用于空Map的named_struct

时间:2017-06-06 18:27:05

标签: scala apache-spark

我使用Spark 2.0.1 Scala 2.11,这个问题与this

有关

以下是设置:

val ss = new StructType().add("x", IntegerType).add("y", MapType(DoubleType, IntegerType))

val s = new StructType()
    .add("a", IntegerType)
    .add("b", ss)

val d = Seq(Row(1, Row(1,Map(1.0->1, 2.0->2))), 
    Row(2, Row(2,Map(2.0->2, 3.0->3))), 
    Row(3, null ), 
    Row(4, Row(4, Map()))) 

val rd = sc.parallelize(d)
val df = spark.createDataFrame(rd, s)

df.select($"a", $"b").show(false)

// +---+---------------------------+
// |a  |b                          |
// +---+---------------------------+
// |1  |[1,Map(1.0 -> 1, 2.0 -> 2)]|
// |2  |[2,Map(2.0 -> 2, 3.0 -> 3)]|
// |3  |null                       |
// |4  |[4,Map()]                  |
// +---+---------------------------+
//

当我必须提供coalesce的默认值(第2行第3行单元格具有默认值)时,以下语句有效:

df.groupBy($"a").pivot("a").
  agg(expr("first(coalesce(b, named_struct('x', cast(null as Int), 'y', Map(0.0D, 0) )))" ) )
  .show(false)

// +---+---------------------------+---------------------------+--------------------+---------+
// |a  |1                          |2                          |3                   |4        |
// +---+---------------------------+---------------------------+--------------------+---------+
// |1  |[1,Map(1.0 -> 1, 2.0 -> 2)]|null                       |null                |null     |
// |3  |null                       |null                       |[null,Map(0.0 -> 0)]|null     |
// |4  |null                       |null                       |null                |[4,Map()]|
// |2  |null                       |[2,Map(2.0 -> 2, 3.0 -> 3)]|null                |null     |
// +---+---------------------------+---------------------------+--------------------+---------+

但是如何使用Map()或其他方式创建一个空的a=4(就像在named_struct中看到的那样)?

1 个答案:

答案 0 :(得分:2)

您可以使用案例类和UDF实现此目的:

case class MyStruct(x:Option[Int], y:Map[Double,Int])

import org.apache.spark.sql.functions.{udf, first,coalesce}

val emptyStruct = udf(() => MyStruct(None,Map.empty[Double,Int]))

df.groupBy($"a").pivot("a")
  .agg(first(coalesce($"b",emptyStruct())))
  .show(false)