具有复合值的RDD键值对

时间:2018-05-28 10:12:59

标签: scala apache-spark aggregate rdd

我这里有一个玩具数据集,我需要计算每个州的城市列表和该州的人口(该州所有城市的人口总和)Data

我想在不使用groupByKey和join的情况下使用RDD来实现。到目前为止我的方法:

在这种方法中,我使用了两个独立的键值对并将它们连接起来。

val rdd1=inputRdd.map(x=>(x._1,x._3.toInt))
val rdd2=inputRdd.map(x=>(x._1,x._2))
val popn_sum=rdd1.reduceByKey(_+_)
val list_cities=rdd2.reduceByKey(_++_)
popn_sum.join(list_cities).collect()

是否可以只使用1个键值对并且没有任何连接来获得相同的输出。 我创建了一个新的键值对,但我不知道如何使用此RDD使用aggregateByKey或reduceByKey来获取相同的输出:

val rdd3=inputRdd.map(x=>(x._1,(List(x._2),x._3))) 

我是新手,想要学习获得此输出的最佳方法。

Array((B,(12,List(B1, B2))), (A,(6,List(A1, A2, A3))), (C,(8,List(C1, C2))))

提前致谢

1 个答案:

答案 0 :(得分:0)

如果您的inputRdd类型为

inputRdd: org.apache.spark.rdd.RDD[(String, String, Int)]

然后,您只需使用一个reduceByKey作为

即可获得所需的结果
inputRdd.map(x => (x._1, (List(x._2), x._3.toInt))).reduceByKey((x, y) => (x._1 ++ y._1, x._2+y._2))

你可以aggregateByKey作为

inputRdd.map(x => (x._1, (List(x._2), x._3.toInt))).aggregateByKey((List.empty[String], 0))((x, y) => (x._1 ++ y._1, x._2+y._2), (x, y) => (x._1 ++ y._1, x._2+y._2))

DataFrame方式

更好的方法是使用数据帧方式。您只需应用.toDF("state", "city", "population")即可将您的rdd转换为数据框

+-----+----+----------+
|state|city|population|
+-----+----+----------+
|A    |A1  |1         |
|B    |B1  |2         |
|C    |C1  |3         |
|A    |A2  |2         |
|A    |A3  |3         |
|B    |B2  |10        |
|C    |C2  |5         |
+-----+----+----------+

之后,您可以使用groupBy,并将collect_listsum内置聚合函数应用为

import org.apache.spark.sql.functions._
inputDf.groupBy("state").agg(collect_list(col("city")).as("cityList"), sum("population").as("sumPopulation"))

应该给你

+-----+------------+-------------+
|state|cityList    |sumPopulation|
+-----+------------+-------------+
|B    |[B1, B2]    |12           |
|C    |[C1, C2]    |8            |
|A    |[A1, A2, A3]|6            |
+-----+------------+-------------+

Dataset几乎相同,但带有额外的类型安全性