Apache Spark RDD中每个唯一键的总和值

时间:2018-01-25 11:11:05

标签: scala apache-spark

我有一个RDD[(String, (Long, Long))],其中每个元素都不是唯一的:

(com.instagram.android,(2,0))
(com.android.contacts,(6,1))
(com.android.contacts,(3,4))
(com.instagram.android,(8,3))
...

所以我想获得一个RDD,其中每个元素是每个唯一键的两个值的总和:

(com.instagram.android,(10,3))
(com.android.contacts,(9,5))
...

这是我的代码:

val appNamesAndPropertiesRdd = appNodesRdd.map({
  case Row(_, appName, totalUsageTime, usageFrequency, _, _, _, _) => 
    (appName, (totalUsageTime, usageFrequency))
})

4 个答案:

答案 0 :(得分:2)

使用reduceByKey

val rdd = appNamesAndPropertiesRdd.reduceByKey(
  (acc, elem) => (acc._1 + elem._1, acc._2 + elem._2)
)

reduceByKey使用SCouto描述的aggregateByKey,但具有更多可读用途。对于您的情况,aggregateByKey的更高级功能 - 由更简单的reduceBykey API隐藏 - 不是必需的

答案 1 :(得分:2)

首先,我认为不应该简单地添加使用频率。

现在,让我们来做你想做的事情,你想按键添加东西,你可以做到这一点

1.使用groupByKey然后reducing小组进行总结,

val requiredRdd = appNamesAndPropertiesRdd
  .groupBy({ case (an, (tut, uf)) => an })
  .map({
    case (an, iter) => (
      an,
      iter
        .map({ case (an, tut, uf) => (tut, tf) })
        .reduce({ case ((tut1, tf1), (tut2, tf2)) => (tut1 + tut2, tf1 + tf2) })
    )
  })

或使用reduceByKey

val requiredRdd = appNamesAndPropertiesRdd
  .reduceByKey({
    case ((tut1, uf1), (tut2, uf2)) => (tut1 + tut2, tf1 + tf2)
  })

reduceByKey是更好的选择,有两个原因,

  1. 它保存了一个不太必要的group操作。
  2. groupBy方法可能导致重新洗牌,这将是昂贵的。

答案 2 :(得分:1)

函数aggregateByKey是用于此目的的最佳函数

appNamesAndPropertiesRdd.aggregateByKey((0, 0))((acc, elem) => (acc._1 + elem._1, acc._2 +elem._2 ),(acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2))

这里解释:
aggregateByKey((0, 0)) =>这是zerovalue。最初的值。在你的情况下,因为你想要加法,如果你想要double而不是int,0,0将是初始值(0.0,0.0)

((acc, elem) => (acc._1 + elem._1, acc._2 +elem._2 ) =>第一个功能。在同一分区中累积元素。累加器将保持部分值。由于elem是一个元组,你需要将它的每一部分添加到累加器的相应部分

(acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)) =>第二个功能。从每个分区累积累加器。

答案 3 :(得分:0)

试试这个逻辑,

rdd.groupBy(_._1).map(x=> (x._1, (x._2.map(_._2).foldLeft((0,0)) {case ((acc1, acc2),(a, b))=> (acc1+a, acc2+b)} )))