【问题标题】:aggregateByKey method not working in spark rddaggregateByKey 方法在 spark rdd 中不起作用
【发布时间】:2019-03-11 20:08:57
【问题描述】:

以下是我的示例数据:

1,Siddhesh,43,32000
1,Siddhesh,12,4300
2,Devil,10,1000
2,Devil,10,3000
2,Devil,11,2000

我创建了pair RDD来执行combineByKeyaggregateByKey操作。以下是我的代码:

val rd=sc.textFile("file:///home/cloudera/Desktop/details.txt").map(line=>line.split(",")).map(p=>((p(0).toString,p(1).toString),(p(3).toLong,p(2).toString.toInt)))  

上面我将前两列的数据配对为键,其余列作为值。现在我只想要数据集中第三列的正确元组中的不同值,我可以使用 combineByKey 来完成。以下是我的代码:

val reduced = rd.combineByKey(
      (x:(Long,Int))=>{(x._1,Set(x._2))},
      (x:(Long,Set[Int]),y:(Long,Int))=>(x._1+y._1,x._2+y._2),
      (x:(Long,Set[Int]),y:(Long,Set[Int]))=>{(x._1+y._1,x._2++y._2)}
      )  
scala> reduced.foreach(println)
((1,Siddhesh),(36300,Set(43, 12)))
((2,Devil),(6000,Set(10, 11)))

现在我映射它,以便我可以获得唯一不同键的值的总和。

scala> val newRdd=reduced.map(p=>(p._1._1,p._1._2,p._2._1,p._2._2.size))

scala> newRdd.foreach(println)
(1,Siddhesh,36300,2)
(2,Devil,6000,2)

这里对于恶魔,最后一个值为 2,因为我在数据集中有 10 个作为“恶魔”记录的 2 个值,并且由于我使用了 Set,它消除了重复项。所以现在我用aggregateByKey 试了一下。以下是我的错误代码:

val rd=sc.textFile("file:///home/cloudera/Desktop/details.txt").map(line=>line.split(",")).map(p=>((p(0).toString,p(1).toString),(p(3).toString.toInt,p(2).toString.toInt)))    

我将 value 列从 long 转换为 int,因为在初始化时它在 '0' 上抛出错误

scala> val reducedByAggKey = rd.aggregateByKey((0,0))(
     |        (x:(Int,Set[Int]),y:(Int,Int))=>(x._1+y._1,x._2+y._2),
     |       (x:(Int,Set[Int]),y:(Int,Set[Int]))=>{(x._1+y._1,x._2++y._2)}
     | )
<console>:36: error: type mismatch;
 found   : scala.collection.immutable.Set[Int]
 required: Int
              (x:(Int,Set[Int]),y:(Int,Int))=>(x._1+y._1,x._2+y._2),
                                                             ^
<console>:37: error: type mismatch;
 found   : scala.collection.immutable.Set[Int]
 required: Int
             (x:(Int,Set[Int]),y:(Int,Set[Int]))=>{(x._1+y._1,x._2++y._2)}
                                                                  ^  

正如 Leo 所建议的,以下是我的错误代码:

    scala> val reduced = rdd.aggregateByKey((0, Set.empty[Int]))(
     |   (x: (Int, Set[Int]), y: (Int, Int)) => (x._1 + y._1, y._2+x._2),
     |   (x: (Int, Set[Int]), y: (Int, Set[Int])) => (x._1 + y._1, y._2++ x._2)
     | )
<console>:36: error: overloaded method value + with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int <and>
  (x: String)String
 cannot be applied to (Set[Int])
         (x: (Int, Set[Int]), y: (Int, Int)) => (x._1 + y._1, y._2+x._2),
                                                                  ^

那我在哪里弄得乱七八糟??请纠正我

【问题讨论】:

  • 我是Leo C的崇拜者
  • 即使我也很佩服你们@thebluephantom 为解决问题所付出的努力

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


【解决方案1】:

如果我正确理解您的要求,要获得完整计数而不是不同计数,请使用 List 而不是 Set 进行聚合。至于你的aggregateByKey 的问题,这是由于zeroValue 的类型不正确,应该是(0, List.empty[Int])(如果你坚持使用Set,应该是(0, Set.empty[Int])):

val reduced = rdd.aggregateByKey((0, List.empty[Int]))(
  (x: (Int, List[Int]), y: (Int, Int)) => (x._1 + y._1, y._2 :: x._2),
  (x: (Int, List[Int]), y: (Int, List[Int])) => (x._1 + y._1, y._2 ::: x._2)
)

reduced.collect
// res1: Array[((String, String), (Int, List[Int]))] =
//   Array(((2,Devil),(6000,List(11, 10, 10))), ((1,Siddhesh),(36300,List(12, 43))))

val newRdd = reduced.map(p => (p._1._1, p._1._2, p._2._1, p._2._2.size))

newRdd.collect
// res2: Array[(String, String, Int, Int)] =
//   Array((2,Devil,6000,3), (1,Siddhesh,36300,2))

请注意,SetList 的更改也适用于您的 combineByKey 代码,如果您想要完整计数而不是不同计数。

[更新]

对于每条评论的不同计数,只需将zeroValue 设置为(0, Set.empty[Int]) 即可使用Set

val reduced = rdd.aggregateByKey((0, Set.empty[Int]))(
  (x: (Int, Set[Int]), y: (Int, Int)) => (x._1 + y._1, x._2 + y._2),
  (x: (Int, Set[Int]), y: (Int, Set[Int])) => (x._1 + y._1, x._2 ++ y._2)
)

reduced.collect
// res3: Array[((String, String), (Int, scala.collection.immutable.Set[Int]))] =
//   Array(((2,Devil),(6000,Set(10, 11))), ((1,Siddhesh),(36300,Set(43, 12))))

【讨论】:

  • 感谢您的回答。但我想要不同的计数。你的代码也适用吗?我可以看到您的输出,它不适用于不同的值。那我该怎么做呢?
  • 那么您只需将原始aggregateByKey 中的zeroValue 更正为Set.empty[Int]。我将扩展我的答案以涵盖不同的计数。
  • :36: error: value :: is not a member of Set[Int] (x: (Int, Set[Int]), y: (Int, Int)) => (x._1 + y._1, y._2 :: x._2), ^ :37: error: value ::: is not a member of Set[Int] (x: (Int, Set[Int ]), y: (Int, Set[Int])) => (x._1 + y._1, y._2 ::: x._2) ^
  • 只需将y._2 + x._2 改回x._2 + y._2 就可以了。例如:Set(1) + 2 可以,但2 + Set(1) 不行。
  • 如果您查看combineByKey 的签名,它的第二个参数需要(C, V) =&gt; C,其中V 是您的PairRDD 的值(即(Long, Int))。
猜你喜欢
  • 2017-08-27
  • 1970-01-01
  • 2015-09-05
  • 2019-04-08
  • 2015-12-07
  • 2021-01-01
  • 2017-10-25
  • 1970-01-01
  • 2014-12-20
相关资源
最近更新 更多