如何将Spark SQL DataFrame与flatMap一起使用?

时间:2015-05-21 18:14:28

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

我正在使用Spark Scala API。我有一个Spark SQL DataFrame(从Avro文件中读取),具有以下模式:

root
|-- ids: array (nullable = true)
|    |-- element: map (containsNull = true)
|    |    |-- key: integer
|    |    |-- value: string (valueContainsNull = true)
|-- match: array (nullable = true)
|    |-- element: integer (containsNull = true)

基本上是2列[​​ids:List [Map [Int,String]],匹配:List [Int]]。示例数据如下:

[List(Map(1 -> a), Map(2 -> b), Map(3 -> c), Map(4 -> d)),List(0, 0, 1, 0)]
[List(Map(5 -> c), Map(6 -> a), Map(7 -> e), Map(8 -> d)),List(1, 0, 1, 0)]
...

我想要做的是flatMap()每行产生3列[ id 属性匹配]。使用上面的2行作为输入数据我们将得到:

[1,a,0]
[2,b,0]
[3,c,1]
[4,d,0]
[5,c,1]
[6,a,0]
[7,e,1]
[8,d,0]
...

然后groupBy String 属性(例如:a,b,...)来生成count("property")sum("match"):< / p>

 a    2    0
 b    1    0
 c    2    2
 d    2    0
 e    1    1

我想做类似的事情:

val result = myDataFrame.select("ids","match").flatMap( 
    (row: Row) => row.getList[Map[Int,String]](1).toArray() )
result.groupBy("property").agg(Map(
    "property" -> "count",
    "match" -> "sum" ) )

问题是flatMap将DataFrame转换为RDD。有没有一种方法可以使用DataFrame进行flatMap类型操作,后跟groupBy

3 个答案:

答案 0 :(得分:10)

flatMap你想做什么?它将每个输入行转换为0行或更多行。它可以过滤掉它们,也可以添加新的。在SQL中,为了获得相同的功能,请使用join。你能用join做你想做的事吗?

或者,您也可以查看Dataframe.explode,它只是一种特定的join(您可以通过将DataFrame连接到UDF来轻松制作自己的explode)。 explode将一列作为输入,并允许您将其拆分或将其转换为多个值,然后将join原始行重新放回新行。所以:

user      groups
griffin   mkt,it,admin

可能成为:

user      group
griffin   mkt
griffin   it
griffin   admin

所以我想说看看DataFrame.explode,如果这不能轻易找到你,请尝试加入UDF。

答案 1 :(得分:0)

我的SQL有点生疏,但是你的flatMap中有一个选项可以生成Row对象列表,然后你可以将生成的RDD转换回DataFrame。

答案 2 :(得分:0)

`myDataFrame.select(explode('ids as "ids",'match).
select( 'ids, explode('match as "match").
map ( r => {
val e=r.getMap[Int,String](0).head
(e._1,e._2,r.getInt(1))
}
)`

groupby ..... 可以在之后运行