如何有选择地从Scala中的一行返回多行

时间:2015-12-18 23:39:36

标签: scala apache-spark

有一个DataFrame,“rawDF”,其列是

time     |id1|id2|...|avg_value|max_value|min_value|std_value|range_value|..
10/1/2015|1  |3  |...|0.0      |0.2      |null     |null     |null     | ...
10/2/2015|2  |3  |...|null     |null     |0.3      |0.4      |null     | ...
10/3/2015|3  |5  |...|null      |null     |null     |0.4      |0.5      | ...

对于每一行,我想基于这五个“值”(avg,min,max,std,range)返回多行。但是,如果值为null,我想跳过。

所以,输出应该是

10/1/2015|1  |3  |...|0.0 
10/1/2015|1  |3  |...|0.2 
10/2/2015|2  |3  |...|0.3
10/2/2015|2  |3  |...|0.4
10/3/2015|3  |5  |...|0.4
10/3/2015|3  |5  |...|0.5

我对Scala不太熟悉,所以,我正在努力解决这个问题。

val procRDD = rawDF.flatMap( x => for(valInd <-10 to 14) yield {
 if(x.get(valInd) != null) { ...)) }
    } )

此代码包含null返回。 那么,你能给我一些想法吗?

2 个答案:

答案 0 :(得分:1)

这有点奇怪的要求,但只要您不需要有关源列的信息,并且所有值都属于同一类型,您只需explode并删除空值:

import org.apache.spark.sql.functions.{array, explode}

val toExpand = Seq(
  "avg_value", "max_value", "min_value", "std_value", "range_value"
)

// Collect *_value columns into a single Array and explode
val expanded = df.withColumn("value", explode(array(toExpand.map(col): _*)))

val result = toExpand
  .foldLeft(expanded)((df, c) => df.drop(c)) // Drop obsolete columns
  .na.drop(Seq("value")) // Drop rows with null value

答案 1 :(得分:0)

这是我的解决方案。如果你有更好的,请告诉我。

val procRDD = rawDF.flatMap( x => 
  for(valInd <-10 to 14) yield { // valInd represents column number
    if(x.get(valInd) != null) {
       try   { Some( ..) }
       catch { case e: Exception => None}
    }else None 
  })
  .filter({case Some(y) => true; case None=> false})
  .map(_.get)

实际上,我一直在寻找filtermap以及如何将命令放入其中。