使用PartitionBy按键拆分和有效计算RDD组

时间:2015-02-09 14:43:21

标签: apache-spark rdd

我已按密钥实施了对RDD[K, V]组的解决方案,并使用(K, RDD[V])partitionBy根据每个组Partitioner计算数据。不过,我不确定它是否真的有效,我想提出你的观点。

以下是一个示例案例:根据[K: Int, V: Int]列表,计算每个V组的K均值,知道它应该分发{{1}值可能非常大。这应该给:

V

简单的Partitioner类:

List[K, V] => (K, mean(V))

分区代码:

class MyPartitioner(maxKey: Int) extends Partitioner {

    def numPartitions = maxKey

    def getPartition(key: Any): Int = key match {
      case i: Int if i < maxKey => i
    }
  }

输出结果为:

val l = List((1, 1), (1, 8), (1, 30), (2, 4), (2, 5), (3, 7)) val rdd = sc.parallelize(l) val p = rdd.partitionBy(new MyPartitioner(4)).cache() p.foreachPartition(x => { try { val r = sc.parallelize(x.toList) val id = r.first() //get the K partition id val v = r.map(x => x._2) println(id._1 + "->" + mean(v)) } catch { case e: UnsupportedOperationException => 0 } })

我的问题是:

  1. 致电1->13, 2->4, 3->7时会发生什么? (对不起,我没有找到足够的规格)
  2. 通过分区进行映射是否真的有效,知道在我的生产情况下,非常多的值(样本为100万)不会太多的密钥(样本为50)
  3. partitionBy的费用是多少?这样做是否一致? (我需要输入paralellize(x.toList)
  4. RDD
  5. 你自己怎么做?
  6. 此致

1 个答案:

答案 0 :(得分:4)

您的代码不起作用。您无法将SparkContext对象传递给执行程序。 (它不是Serializable。)我也不明白你为什么需要这样做。

要计算平均值,您需要计算总和和计数并取其比率。默认分区程序就可以了。

def meanByKey(rdd: RDD[(Int, Int)]): RDD[(Int, Double)] = {
  case class SumCount(sum: Double, count: Double)
  val sumCounts = rdd.aggregateByKey(SumCount(0.0, 0.0))(
    (sc, v) => SumCount(sc.sum + v, sc.count + 1.0),
    (sc1, sc2) => SumCount(sc1.sum + sc2.sum, sc1.count + sc2.count))
  sumCounts.map(sc => sc.sum / sc.count)
}

这是一种有效的单程计算,可以很好地推广。