Scala 提高distinct+的性能;Spark上的groupByKey

Scala 提高distinct+的性能;Spark上的groupByKey,scala,apache-spark,Scala,Apache Spark,我正在努力学习spark,并提出了这个问题,但我的解决方案似乎效果不佳。我希望有人能教我如何提高成绩。我的问题如下 我有几百万个元组(例如,(a,B),(a,C),(B,C)等等),可能有重复的元组(键和值)。我想做的是按键对元组进行分组,为了让它更有趣,将分组值的长度限制为任意数字(比如3) 例如,如果我有: [(A, B), (A, C), (A, D), (A, E), (B, C)] 我预计产出为: [(A, [B, C, D]), (A, [E]), (B, [C])) 如果列表中

我正在努力学习spark,并提出了这个问题,但我的解决方案似乎效果不佳。我希望有人能教我如何提高成绩。我的问题如下

我有几百万个元组(例如,(a,B),(a,C),(B,C)等等),可能有重复的元组(键和值)。我想做的是按键对元组进行分组,为了让它更有趣,将分组值的长度限制为任意数字(比如3)

例如,如果我有:

[(A, B), (A, C), (A, D), (A, E), (B, C)]
我预计产出为:

[(A, [B, C, D]), (A, [E]), (B, [C]))
如果列表中的任何值超过3,那么它会将其拆分,并使用(A,[E])多次列出同一个键。希望这是有道理的

我想出的解决办法是:

val myTuples: Array[(String, String)] = ...
sparkContext.parallelize(myTuples)
            .distinct()             // to delete duplicates
            .groupByKey()           // to group up the tuples by key
            .flatMapValues(values => values.grouped(3)) // split up values in groups of 3
            .repartition(sparkContext.defaultParallelism)
            .collect()
我的解决方案还可以,但有没有更有效的方法?我听说groupByKey效率很低。任何帮助都将不胜感激

还有,我应该为分区选择一个合适的数字吗?我注意到
distinct
接受了
partition
参数,但不确定应该放什么


谢谢

您需要稍微重新表述您的问题,因为您实际上并不是按单个键进行分组;在上面的示例中,您为“A”输出了多行。在下面,我添加了一列,我们还可以使用它来分组(它将每3条记录递增一次),并收集_list,这是一个Spark SQL函数,用于生成您要查找的数组。请注意,通过完全使用Spark SQL,您可以从Spark获得许多优化(通过“catalyst”这一查询优化程序)


我注意到你没有明确地说你想去掉这些复制品。如果要消除它们,请在开始时使用.distinct。distinct方法上的DataFrames没有分区参数(如果您可以使用DataFrames而不是RDD,通常这是正确的选择,因为您从catalyst获得了优化)。感谢@Nick的帮助。这太棒了。是的,输出包含多个“A”的原因是由于限制值的长度应小于或等于3。现在,我使用的是数据集(RDD)而不是数据帧。使用数据帧而不是数据集有什么缺点(具体到本例中)?RDD和数据集实际上是不同的东西。为了向您证明这一点,请尝试运行myTuples.toList.toDS()。对于您的问题,是的,有一个优势-您使用催化剂优化程序。Catalyst的存在使您不必担心以最有效的方式编写每个查询(例如,Spark将只从磁盘读取所需的列,它避免了不必要的数据结构,…)。完全解释RDD、DataFrame和Dataset的范围本身就是几个StackOverflow,但是google有很多解释差异的地方。
import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

val data = List(("A", "B"), ("A", "C"), ("A", "D"), ("A", "E"), ("B", "C")).toDF("key","value")

val data2 = data.withColumn("index", floor(
  (row_number().over(Window.partitionBy("key").orderBy("value"))-1)/3)
)
data2.show

+---+-----+-----+
|key|value|index|
+---+-----+-----+
|  B|    C|    0|
|  A|    B|    0|
|  A|    C|    0|
|  A|    D|    0|
|  A|    E|    1|
+---+-----+-----+

data2.groupBy("key","index").agg(collect_list("value")).show

+---+-----+-------------------+
|key|index|collect_list(value)|
+---+-----+-------------------+
|  B|    0|                [C]|
|  A|    0|          [B, C, D]|
|  A|    1|                [E]|
+---+-----+-------------------+