按键减少和求和元组

时间:2018-10-19 18:31:39

标签: scala apache-spark rdd reduce

在我的Spark Scala应用程序中,我具有以下格式的RDD:

(05/05/2020, (name, 1))
(05/05/2020, (name, 1))
(05/05/2020, (name2, 1))
...
(06/05/2020, (name, 1))

我要做的是按日期对这些元素进行分组,并对具有与键相同的“名称”的元组求和。

预期输出:

(05/05/2020, List[(name, 2), (name2, 1)]),
(06/05/2020, List[(name, 1)])
...

为此,我目前正在使用groupByKey操作和一些额外的转换,以便按键对元组进行分组,并为共享相同元组的元组求和。

出于性能方面的考虑,我想将此groupByKey操作替换为reduceByKeyaggregateByKey,以减少通过网络传输的数据量。

但是,我无法确定如何做到这一点。这两个转换都将值(在本例中为元组)之间的函数作为参数,因此我看不到如何按键对元组进行分组以计算其总和。

这可行吗?

3 个答案:

答案 0 :(得分:0)

是的def is_bipartite(v, visited, colors, counter): visited[v] = True colors[v] = counter % 2 for u in v.links: if u in visited: if colors[v] == colors[u]: return False # return instead of raise in this base case if u not in visited: visited[u] = False if not is_bipartite(u, visited, colors, counter + 1): # check the recursion return False # pass on any False return True # return True only if you got to the end without returning False above 可以按以下方式使用:

.aggeregateBykey()

积分:Best way to merge two maps and sum the values of same key?

答案 1 :(得分:0)

以下是使用reduceByKey合并元组的方法:

/**
File /path/to/file1:
15/04/2010  name
15/04/2010  name
15/04/2010  name2
15/04/2010  name2
15/04/2010  name3
16/04/2010  name
16/04/2010  name

File /path/to/file2:
15/04/2010  name
15/04/2010  name3
**/

import org.apache.spark.rdd.RDD

val filePaths = Array("/path/to/file1", "/path/to/file2").mkString(",")

val rdd: RDD[(String, (String, Int))] = sc.textFile(filePaths).
  map{ line =>
    val pair = line.split("\\t", -1)
    (pair(0), (pair(1), 1))
  }

rdd.
  map{ case (k, (n, v)) => (k, Map(n -> v)) }.
  reduceByKey{ (acc, m) =>
    acc ++ m.map{ case (n, v) => (n -> (acc.getOrElse(n, 0) + v)) }
  }.
  map(x => (x._1, x._2.toList)).
  collect
// res1: Array[(String, List[(String, Int)])] = Array(
//   (15/04/2010, List((name,3), (name2,2), (name3,2))), (16/04/2010, List((name,2)))
// )

请注意,由于我们希望将元组合并为Map中的元素,因此需要初始映射,而对于RDD [K,V],reduceByKey需要相同的数据类型V转换前后:

def reduceByKey(func: (V, V) => V): RDD[(K, V)]

答案 2 :(得分:0)

您可以将RDD转换为DataFrame,而仅将groupBy与sum一起使用,这是一种实现方法

import org.apache.spark.sql.types._
val schema = StructType(StructField("date", StringType, false) :: StructField("name", StringType, false) ::  StructField("value", IntegerType, false) :: Nil)

val rd = sc.parallelize(Seq(("05/05/2020", ("name", 1)),
("05/05/2020", ("name", 1)),
("05/05/2020", ("name2", 1)),
("06/05/2020", ("name", 1))))

val df = spark.createDataFrame(rd.map{ case (a, (b,c)) => Row(a,b,c)},schema)
df.show

+----------+-----+-----+
|      date| name|value|
+----------+-----+-----+
|05/05/2020| name|    1|
|05/05/2020| name|    1|
|05/05/2020|name2|    1|
|06/05/2020| name|    1|
+----------+-----+-----+

val sumdf = df.groupBy("date","name").sum("value")
sumdf.show

+----------+-----+----------+
|      date| name|sum(value)|
+----------+-----+----------+
|06/05/2020| name|         1|
|05/05/2020| name|         2|
|05/05/2020|name2|         1|
+----------+-----+----------+