在spark中有效地操作RDD键的子集

时间:2016-01-22 05:26:06

标签: scala apache-spark

我有一个表格

的(键,值)对的RDD
RDD[(
  scala.collection.immutable.Vector[(Byte, Byte)],   
  scala.collection.immutable.Vector[Int]
)]

其中keyVector[(Byte, Byte)]valueVector[Int]

例如,RDD的内容可以如下所示。

(Vector((3,3), (5,5)), Vector(1, 2)),
(Vector((1,1), (2,2), (3,3),(4,4), (5,5)), Vector(1, 3, 4, 2)), 
(Vector((1,1), (2,3)), Vector(1, 4, 2)), 
(Vector((1,1), (2,2), (5,5)), Vector(3, 5)),

我想对这个RDD进行操作,以便在结果RDD中,对于每个(键,值)对,满足以下条件。

当此RDD的键'k1'是此RDD的键'k2'的子集时,k1的值也应更新为包含k2的值,而k2的值将保持不变。

以上示例RDD将成为

(Vector((3,3), (5,5)), Vector(1, 2, 3, 4)), 
(Vector((1,1), (2,2), (3,3), (4,4), (5,5)), Vector(1, 3, 4, 2))
(Vector((1,1), (2,3)), Vector(1, 4, 2))
(Vector((1,1), (2,2), (5,5)), Vector(1, 2, 3, 4, 5))

我问了一个类似的问题here。提供的解决方案如下(稍作修改以适应我的问题)。这适用于大型数据集但效率很低。

val resultPre = rddIn
  .flatMap { case (colMapkeys, rowIds) => 
    colMapkeys.subsets.tail.map(_ -> rowIds)
  }
  .reduceByKey(_ ++ _)
  .join(rddIn map identity[(Seq[(Byte, Byte)], Vector[Int])])
  .map{ case (key, (v, _)) => (key, v) }


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 +: _)
    }
  }
}

生成所有密钥子集,然后通过加入原始RDD密钥对其进行过滤似乎是无效的。

我如何有效地处理这个问题?

1 个答案:

答案 0 :(得分:1)

我认为你的问题基本上很难。你基本上有两种方法可以做到这一点:

  1. 生成所有子集键,合并值列表并收集任何给定子集的fina列表,然后仅加入现有子集。 (这就是你要做的)。

  2. 将每个条目与其他条目进行比较,查看一个键是否是另一个键的子集,然后合并按键生成的所有子集。这不会产生虚假的密钥中间排列。

  3. 哪一个更有效将取决于数据的性质(关键向量的大小,它们是彼此的子集的次数等)。

    您可以尝试的其他优化是使数据更容易处理。例如,您可以安全地将内部坐标映射到整数(它们只是字节)。说(5,5)到5 * 1000 + 5 = 5005.因为整数比较比比较元组更容易,更快。

    取决于您对密钥域的理解程度。如果此空间足够小,您可以尝试将密钥表示为位图或其他类似的位置。这些更改不会从根本上改变您拥有的密钥数量,但可能会使比较和其他操作更容易。