火花scala中向量的子集操作

时间:2015-12-08 06:42:27

标签: scala apache-spark

我有

形式的RDD curRdd
res10: org.apache.spark.rdd.RDD[(scala.collection.immutable.Vector[(Int, Int)], Int)] = ShuffledRDD[102]

curRdd.collect()会产生以下结果。

Array((Vector((5,2)),1), (Vector((1,1)),2), (Vector((1,1), (5,2)),2))

此处:整数对的矢量和:count

现在,我希望通过渗透计数将其转换为相同格式RDD[(scala.collection.immutable.Vector[(Int, Int)], Int)]的另一个RDD。

(Vector((1,1), (5,2)),2)) (Vector((5,2)),1)会将其计数为2的任何键,其中(Vector((5,2)),3)成为(Vector((5,2)),3), (Vector((1,1)),4), (Vector((1,1), (5,2)),2)

对于上面的示例,我们的新RDD将具有

{{1}}

我如何实现这一目标?请帮助。

1 个答案:

答案 0 :(得分:2)

首先,您可以为subsets引入Seq操作:

implicit class SubSetsOps[T](val elems: Seq[T]) extends AnyVal {
    def subsets: Vector[Seq[T]] = elems match {
      case Seq() => Vector(elems)
      case elem +: rest => {
        val recur = rest.subsets
        recur ++ recur.map(elem +: _)
      }
    }
  }

empty子集将始终是结果向量中的第一个元素,因此您可以使用.tail

省略它

现在您的任务非常明显 map - reduce ,其中 flatMap - reduceByKey RDD

 val result = curRdd
      .flatMap { case (keys, count) => keys.subsets.tail.map(_ -> count) }
      .reduceByKey(_ + _)

更新

此实现可能会在结果中引入新的集合,如果您只想选择原始集合中显示的那些集合,您可以将结果与原始集合结合:

val result = curRdd
  .flatMap { case (keys, count) => keys.subsets.tail.map(_ -> count) }
  .reduceByKey(_ + _)
  .join(curRdd map identity[(Seq[(Int, Int)], Int)])
  .map { case (key, (v, _)) => (key, v) }

请注意,需要map identity步骤才能将原始Vector[_]中的密钥类型从Seq[_]转换为RDD。您可以修改SubSetsOps定义,用Seq[T]替换所有Vector[T]或更改定义(硬编码scala.collection)方式:

import scala.collection.SeqLike
import scala.collection.generic.CanBuildFrom

implicit class SubSetsOps[T, F[e] <: SeqLike[e, F[e]]](val elems: F[T]) extends AnyVal {
    def subsets(implicit cbf: CanBuildFrom[F[T], T, F[T]]): Vector[F[T]] = elems match {
      case Seq() => Vector(elems)
      case elem +: rest => {
        val recur = rest.subsets
        recur ++ recur.map(elem +: _)
      }
    }
  }