如何在数据框中将水平数据扩展为垂直数据?

时间:2019-06-13 09:06:35

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

我有一个文本文件。现在,我想将水平数据扩展为垂直数据。 使用指定文件的第一个字段中的字段作为关键字,将水平排列的字段数据垂直扩展并重新排列。我该怎么办?

这是我的输入:

0000000 aa______ 50 F 91 59 20 76 
0000001 bb______ 50 F 46 39 8 5 
0000003 cc______ 26 F 30 50 71 36 
0000004 dd______ 40 M 58 71 20 10

Exp1:现在,我想每2个字段垂直开发一次,并且第一个值保留在每一行上。我希望获得期望的输出结果,如下所示。

0000000 aa______ 50 
0000000 F 91 
0000000 59 20 
0000000 76 
0000001 bb______ 50 
0000001 F 46 
0000001 39 8 
0000001 5 
0000003 cc______ 26 
0000003 F 30 
0000003 50 71 
0000003 36 
0000004 dd______ 40 
0000004 M 58 
0000004 71 20 
0000004 10

Exp2:与上面相同,但在每行上保留前两个值。

0000000 aa______ 50 F 
0000000 aa______ 91 59 
0000000 aa______ 20 76 
0000001 bb______ 50 F 
0000001 bb______ 46 39 
0000001 bb______ 8 5 
0000003 cc______ 26 F 
0000003 cc______ 30 50 
0000003 cc______ 71 36 
0000004 dd______ 40 M 
0000004 dd______ 58 71 
0000004 dd______ 20 10

这是我的代码,但无法正常工作。

val df = sc.textFile("/home/ubuntu/spark-2.4.3-bin-hadoop2.6/data.txt"); 
val splitRdd = df.map{s => val a = s.split("[ |]") 
var i = 0; 
val date = Array(a(i) + " " + a(i+1) + " " + a(i+2) + " " + a(i+3) + " " + a(i+4)) 
(date ++ a.takeRight(0)).mkString(" ") 
} 
splitRdd.foreach(println)

1 个答案:

答案 0 :(得分:1)

使用UDF最容易解决:

def splitValues(nKeys: Int, nGroup: Int) = udf((str: String) => {
  val vals = str.split(" ")
  val key = vals.take(nKeys)
  vals.drop(nKeys).grouped(nGroup).toSeq.map(e => (key ++ e).mkString(" "))
})

UDF接受两个输入,nKeys是用作键的值的数量,nGroup是每行要保留的值的数量(除了键)。 UDF将返回一个数组,因此您需要在应用explode后使用它。

带有一个键值的用法示例:

val df = spark.read.text("test.txt")
df.select(explode(splitValues(1, 2)($"value")))

+-------------------+
|col                |
+-------------------+
|0000000 aa______ 50|
|0000000 F 91       |
|0000000 59 20      |
|0000000 76         |
|0000001 bb______ 50|
|0000001 F 46       |
|0000001 39 8       |
|0000001 5          |
|0000003 cc______ 26|
|0000003 F 30       |
|0000003 50 71      |
|0000003 36         |
|0000004 dd______ 40|
|0000004 M 58       |
|0000004 71 20      |
|0000004 10         |
+-------------------+

具有两个键值:

df.select(explode(splitValues(2, 2)($"value")))

+----------------------+
|col                   |
+----------------------+
|0000000 aa______ 50 F |
|0000000 aa______ 91 59|
|0000000 aa______ 20 76|
|0000001 bb______ 50 F |
|0000001 bb______ 46 39|
|0000001 bb______ 8 5  |
|0000003 cc______ 26 F |
|0000003 cc______ 30 50|
|0000003 cc______ 71 36|
|0000004 dd______ 40 M |
|0000004 dd______ 58 71|
|0000004 dd______ 20 10|
+----------------------+