如何在使用reducebykey时限制单个记录中的对数

时间:2018-07-31 22:28:37

标签: scala apache-spark

我的输入如下。

输入:

key,A,1
key,A,2
key,A,3
key,A,4
key,A,5
key,A,6

我正在使用以下代码实现我的第一个输出

val finalOutputRDD = AddDeletesRDD.map(x => ( x.split("~").slice(0, endOfKeyPosition).mkString(","), x.split("~").slice(0, 1).mkString(",") + "~" + x.split("~").slice(3, 4).mkString(",") ))
 .sortByKey()                                      
 .reduceByKey((key, value) => key +"|" + value)
 .map(records => records._1 + "," + records._2)

finalOutputRDD.saveAsTextFile(deltaFileLocation)

我的输出是:

key,A~1|A~2|A~3|A~4|A~5|A~6|

现在,我想动态传递一个值(例如3),我想要以下输出:

key,A~1|A~2|A~3
key,A~4|A~5|A~6

2 个答案:

答案 0 :(得分:0)

我认为您必须对密钥进行分组,然后生成作为密钥加整数的新密钥,然后对这些密钥进行重新分组,最后丢弃生成的整数。像这样:

def reduceByKeyMaxN[K, V](rdd: RDD[(K, V)], n: Int, f: (V, V) => V): RDD[(K, V)] = {
  rdd
    .groupByKey()
    .flatMap { case (k, vs) =>
      vs.zipWithIndex.map{ case (v, i) => ((k, i / n), v) }
    }
    .reduceByKey(f)
    .map { case ((k, _), v) => (k, v) }
 }

然后,您可以将对代码中对reduceByKey的调用替换为对此方法的调用。

答案 1 :(得分:0)

如果我正确理解了您的要求,这是一种方法:

  1. 将数据集转换为对-RDD并应用reduceByKey以生成(key,Seq(values))的RDD
  2. flatMap使用grouped(n)将结果数据集划分为(键,值)的分组列表
  3. 最后将每个分组列表reduce放入RDD(键,分组值字符串)

以下是示例代码,其中的数据集更为通用:

val rdd = sc.parallelize(Seq(
  ("k1", "A", 1),
  ("k1", "A", 2),
  ("k1", "A", 3),
  ("k1", "A", 4),
  ("k1", "A", 5),
  ("k1", "A", 6),
  ("k2", "B", 1),
  ("k2", "B", 2),
  ("k2", "B", 3),
  ("k2", "B", 4)
))

val n = 3

rdd.map{ case (k, s, i) => (k, Seq(s + "~" + i)) }.
  reduceByKey( _ ++ _ ).
  flatMap{ case (k, vs) => vs.map(i => (k, i)).grouped(n) }.
  map( _.reduce( (acc, x) => (acc._1, (acc._2 + "|" + x._2)) ) ).
  collect
// res1: Array[(String, String)] =
//   Array((k1,A~1|A~2|A~3), (k1,A~4|A~5|A~6), (k2,B~1|B~2|B~3), (k2,B~4))