RDD按键删除元素

时间:2016-04-27 14:32:19

标签: scala apache-spark rdd

我有两个RDD,使用以下代码:

val fileA = sc.textFile("fileA.txt")
val fileB = sc.textFile("fileB.txt")

然后我按键映射并减少它:

val countsB = fileB.flatMap(line => line.split("\n"))
  .map(word => (word, 1))
  .reduceByKey(_+_)

val countsA = fileA.flatMap(line => line.split("\n"))
  .map(word => (word, 1))
  .reduceByKey(_+_)

如果密钥存在于countA

中,我现在不想找到并删除co​​untB中的所有密钥

我尝试过类似的事情:

countsB.keys.foreach(b => {
  if(countsB.collect().exists(_ == b)){
    countsB.collect().drop(countsB.collect().indexOf(b))
  }
})

但似乎它不会被密钥删除它们。

1 个答案:

答案 0 :(得分:3)

您建议的代码有3个问题:

  1. 您正在collect RDD,这意味着它们不再是RDD,它们作为普通的Scala集合被复制到驱动程序应用程序的内存中,因此您将失去Spark的并行性并冒着OutOfMemory错误的风险,以防您的数据集很大

  2. 在不可变的Scala集合(或drop)上调用RDD时,您不会更改原始集合,而是获得 new 集合那些记录丢失了,所以你不能指望原始集合改变

  3. 您无法访问传递给任何RDD高阶方法的函数中的RDD(例如,在这种情况下为foreach) - 传递给这些方法的任何函数都被序列化并发送对于工作者而言,RDD是(故意)不可序列化的 - 将它们提取到驱动程序内存,序列化它们并发送回工作人员是没有意义的 - 数据已经分发给工作人员了!

  4. 要解决所有这些问题 - 当您想要使用一个RDD数据来转换/过滤另一个数据时,通常需要使用某种类型的 join 。在这种情况下,你可以这样做:

    // left join, and keep only records for which there was NO match in countsA:
    countsB.leftOuterJoin(countsA).collect { case (key, (valueB, None)) => (key, valueB) }
    

    请注意,我在这里使用的collect不是您使用的collect - 这个PartialFunction作为参数,行为类似map的组合1}}和filter,最重要的是:它不会将所有数据复制到驱动程序内存中。

    编辑:正如The Archetypal Paul所评论的那样 - 你有一个更短更好的选择 - subtractByKey

    countsB.subtractByKey(countsA)