如何从spark数据帧

时间:2017-11-23 20:33:22

标签: scala apache-spark

我有一个带有以下架构和类数据的spark数据帧:

>ab
ab: org.apache.spark.sql.DataFrame = [block_number: bigint, collect_list(to): array<string> ... 1 more field]

>ab.printSchema
root |-- block_number: long (nullable = true) 
     |-- collect_list(to): array (nullable = true) 
     | |-- element: string (containsNull = true) 
     |-- collect_list(from): array (nullable = true) 
     | |-- element: string (containsNull = true)

我想简单地合并这两列中的数组。我试图在网上找到一个简单的解决方案,但没有运气。基本上我的问题归结为两个问题。

首先,我知道解决方案可能涉及地图功能。我无法找到任何可以实际编译的语法,所以现在请接受我最好的尝试:

ab.rdd.map(
  row => {
  val block = row.getLong(0)
  val array1 = row(1).getAs[Array<string>]
  val array1 = row(1).getAs[Array<string>]
  }
)

基本上问题1非常简单,并且自从我第一次开始在Scala中使用map之后一直重复出现的问题:我无法弄清楚如何从列中提取任意类型的任意字段。我知道对于原始类型,你有row.getLong(0)之类的东西,但是我不明白如何对数组类型这样做。

我在某处看到像row.getAs[Array<string>](1)这样的东西应该有用,但是当我尝试它时我得到了错误

error: identifier expected but ']' found.
  val array1 = row.getAs[Array<string>](1)`

据我所知,这正是我在其他情况下看到的语法,但我不知道为什么它不起作用。我想我之前看到的其他语法看起来像row(1).getAs[Type],但我不确定。

第二个问题是:一旦我可以接触这两个数组,合并它们的最佳方法是什么?使用交叉函数?或者对整个过程有更好的方法吗?例如使用砖房包装?

任何帮助将不胜感激。

最佳,

1 个答案:

答案 0 :(得分:0)

您不需要切换到RDD API,您可以使用Dataframe UDF这样做:

val mergeArrays = udf((arr1:Seq[String],arr2:Seq[String]) => arr1++arr2)

df
  .withColumn("merged",mergeArrays($"collect_list(from)",$"collect_list(to)"))
  .show()

上面的UDF只是对数组进行汇总(使用++运算符),您还可以使用unionintersect等,具体取决于您想要实现的目标。

使用RDD API,解决方案如下所示:

df.rdd.map(
     row => {
       val block = row.getLong(0)
       val array1 = row.getAs[Seq[String]](1)
       val array2 = row.getAs[Seq[String]](2)
       (block,array1++array2)
     }
  ).toDF("block","merged") // back to Dataframes