ReduceByKey对元组的可迭代值

时间:2018-09-15 15:28:43

标签: scala apache-spark rdd

我正在尝试计算特定日期特定物品的出现。

我输入的结构为Date\tItem1:AppearencesOfItem1,...,ItemN:AppearencesOfItemN

示例

20/10/2000\tItem1:1,Item2:5
20/10/2000\tItem1:2
21/10/2000\tItem1:5

为此,我创建了以下PairRdd结构:

[(20/10/2000, (Item1, 1))
(20/10/2000, (Item2, 5))
(20/10/2000, (Item1, 5))
(21/10/2000, (Item1, 5))]

,然后是groupByKey,该日期导致:

[(20/10/2000, Iterable[(Item1, 1), (Item2, 5), (Item1, 5))
 (21/10/2000, Iterable[(Item1, 5)]

此步骤后,我想做的就是减小这些对的值,并对具有相同密钥的项的外观求和,以使结果变为:

[(20/10/2000, Iterable[(Item1, 6), (Item2, 5))
 (21/10/2000, Iterable[(Item1, 5)]

但是我还没有找到减少这些pairRdds值的方法。我的方法首先是错误的吗?

2 个答案:

答案 0 :(得分:2)

可以通过两个步骤实现:

  1. 前两列之和
  2. GroupBy(或为性能降低reduceBy)的第一列

    val data = List( 
      ("20/10/2000", "Item1", 1),
      ("20/10/2000", "Item2", 5),
      ("20/10/2000", "Item1", 5),
      ("21/10/2000", "Item1", 5)
    )
    val originalRDD = sparkContext.parallelize(data)
    
    val sumRDD = originalRDD.map(v => ((v._1, v._2), v._3)).reduceByKey(_ + _)
    sumRDD.map(v => ((v._1._1), (v._1._2, v._2))).groupByKey().foreach(println)
    

输出:

(21/10/2000,CompactBuffer((Item1,5)))
(20/10/2000,CompactBuffer((Item1,6), (Item2,5)))

答案 1 :(得分:1)

希望这会有所帮助,这也许不是他最优雅的方式,但似乎符合您的要求:

rdd.groupByKey.mapValues(x => x.groupBy(_._1).mapValues(x => x.map(_._2).sum))

首先将您的值映射到按itemId分组,然后在该分组列表上,再次映射值以仅保留第二个元素(整数),这样您就可以直接对其求和

输出:

scala> rdd.groupByKey.mapValues(x => x.groupBy(_._1).mapValues(x => x.map(_._2).sum)).foreach(println)
(21/10/2000,Map(Item1 -> 5))
(20/10/2000,Map(Item2 -> 5, Item1 -> 6))

修改 我是在RDD内创建地图,如果您希望将其作为List或仅执行toList

rdd.groupByKey.mapValues(x => x.groupBy(_._1).mapValues(x => x.map(_._2).sum).toList)