将DataFrame中的元组聚合在一起

时间:2018-06-15 15:53:32

标签: apache-spark pyspark apache-spark-sql

我目前正在尝试对服务列进行一些聚合。我想对所有类似的服务进行分组并对值进行求和,如果可能的话,将其展平为一行。

输入:

+------------------+--------------------+
|         cid      |            Services|
+------------------+--------------------+
|845124826013182686|     [112931, serv1]|
|845124826013182686|     [146936, serv1]|
|845124826013182686|      [32718, serv2]|
|845124826013182686|      [28839, serv2]|
|845124826013182686|       [8710, serv2]|
|845124826013182686|    [2093140, serv3]|

希望输出:

+------------------+--------------------+------------------+--------------------+
|         cid      |            serv1   |    serv2         |      serv3         |               
+------------------+--------------------+------------------+--------------------+
|845124826013182686|             259867 |            70267 |            2093140 |

以下是我目前的代码

from pyspark.sql import SparkSession, functions
spark = SparkSession.builder.appName("Service Aggregation").getOrCreate()
pathToFile = '/path/to/jsonfile'
df = spark.read.json(pathToFile)
df2 = df.select('cid',functions.explode_outer(df.nodes.services))
finaldataFrame = df2.select('cid',(functions.explode_outer(df2.col)).alias('Services'))
finaldataFrame.show()

我对pyspark很新,并且一直在寻找资源并尝试创建一些UDF来应用于该列,但是带有ipyspark的map函数仅适用于RDD而不是DataFrames,并且我不确定如何向前移动以获得所需的输出

非常感谢任何建议或帮助。

printSchema的结果

root
 |-- clusterId: string (nullable = true)
 |-- col: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- cpuCoreInSeconds: long (nullable = true)
 |    |    |-- name: string (nullable = true)

1 个答案:

答案 0 :(得分:2)

首先,按位置从Services列中提取服务和值。请注意,这假设值始终位于位置0,服务始终位于位置1(如示例所示)。

import pyspark.sql.functions as f
df2 = df.select(
    'cid',
    f.col("Services").getItem(0).alias('value').cast('integer'),
    f.col("Services").getItem(1).alias('service')
)

df2.show()
#+------------------+-------+-------+
#|               cid|  value|service|
#+------------------+-------+-------+
#|845124826013182686| 112931|  serv1|
#|845124826013182686| 146936|  serv1|
#|845124826013182686|  32718|  serv2|
#|845124826013182686|  28839|  serv2|
#|845124826013182686|   8710|  serv2|
#|845124826013182686|2093140|  serv3|
#+------------------+-------+-------+

请注意,我将value转换为integer,但它可能已经是一个整数,具体取决于您的架构的定义方式。

一旦数据采用这种格式,就很容易pivot()。按cid列分组,转动service列,并通过汇总value列进行汇总:

df2.groupBy('cid').pivot('service').sum("value").show()
#+------------------+------+-----+-------+
#|               cid| serv1|serv2|  serv3|
#+------------------+------+-----+-------+
#|845124826013182686|259867|70267|2093140|
#+------------------+------+-----+-------+

<强>更新

根据您提供的架构,您必须按名称而不是按位置获取价值和服务:

df2 = df.select(
    'cid',
    f.col("Services").getItem("cpuCoreInSeconds").alias('value'),
    f.col("Services").getItem("name").alias('service')
)

其余的都是一样的。此外,无需转换为整数,因为cpuCoreInSeconds已经是long