拆分单行的多个字段或列,并使用Scala创建多个行

时间:2016-07-14 22:09:51

标签: scala apache-spark dataframe

我有一个包含4个字段的数据框,如下所述:

Field1 , Field2 , Field3 , Field4

我在以下字段中有值:

A1      , B1         , C1         , D1                
A2      , B2,B3      , C2,C3      , D2,D3             
A1      , B4,B5,B6   , C4,C5,C6   , D4,D5,D6          

我必须将其转换为以下格式:

A1      , B1         , C1         , D1          
A2      , B2         , C2         , D2            
A2      , B3         , C3         , D3      
A1      , B4         , C4         , D4      
A1      , B5         , C5         , D5      
A1      , B6         , C6         , D6      

基本上我必须在多列中拆分逗号分隔值,并根据相同顺序的值形成新行。

您可以将所有类型视为字符串类型。您能否建议我根据新值进行拆分和形成新行的方法。

我可以看到一个类似于下面的问题:

如何在Spark中嵌套数据框

但是这个问题不同,因为在这种情况下我必须考虑拆分多个列,并且值不应重复。

2 个答案:

答案 0 :(得分:3)

您可以将DataFrame转换为Dataset[(String, String, String, String)]flatMap

import scala.util.Try

val df = Seq(
  ("A1", "B1", "C1", "D1"),
  ("A2", "B2,B3", "C2,C3", "D2,D3"),
  ("A1", "B4,B5,B6", "C4,C5,C6", "D4,D5,D6")
).toDF("x1", "x2", "x3", "x4")

// A simple sequence of expressions which allows us to flatten the results
val exprs = (0 until df.columns.size).map(i => $"value".getItem(i))

df.select($"x1", array($"x2", $"x3", $"x4")).as[(String, Seq[String])].flatMap {
  case (x1, xs) => 
    Try(xs.map(_.split(",")).transpose).map(_.map("x" +: _)).getOrElse(Seq())
}.toDF.select(exprs:_*)

// +--------+--------+--------+--------+
// |value[0]|value[1]|value[2]|value[3]|
// +--------+--------+--------+--------+
// |      A1|      B1|      C1|      D1|
// |      A2|      B2|      C2|      D2|
// |      A2|      B3|      C3|      D3|
// |      A1|      B4|      C4|      D4|
// |      A1|      B5|      C5|      D5|
// |      A1|      B6|      C6|      D6|
// +--------+--------+--------+--------+

或使用UDF:

val splitRow = udf((xs: Seq[String]) => 
   Try(xs.map(_.split(",")).transpose).toOption)

// Same as before but we exclude the first column
val exprs = (0 until df.columns.size - 1).map(i => $"xs".getItem(i))

df
  .withColumn("xs", explode(splitRow(array($"x2", $"x3", $"x4"))))
  .select($"x1" +: exprs: _*)

答案 1 :(得分:0)

您可以使用posexplode快速解决此问题。请参阅http://allabouthadoop.net/hive-lateral-view-explode-vs-posexplode/ 因此,您的代码将如下所示:

{
      id: 2,
      title: 'testevent',
      start: new Date(2020, 4, 29),
      end: new Date(2020, 5, 26),


  },