Scala Spark:拆分成几个RDD?

时间:2014-12-01 15:20:40

标签: scala apache-spark

是否有任何Spark函数允许根据某些creteria将集合拆分为多个RDD?这样的功能可以避免过度的迭代。例如:

def main(args: Array[String]) {
    val logFile = "file.txt" 
    val conf = new SparkConf().setAppName("Simple Application")
    val sc = new SparkContext(conf)
    val logData = sc.textFile(logFile, 2).cache()
    val lineAs = logData.filter(line => line.contains("a")).saveAsTextFile("linesA.txt")
    val lineBs = logData.filter(line => line.contains("b")).saveAsTextFile("linesB.txt")
  }

在这个例子中,我必须迭代“logData”两次才能将结果写入两个单独的文件中:

    val lineAs = logData.filter(line => line.contains("a")).saveAsTextFile("linesA.txt")
    val lineBs = logData.filter(line => line.contains("b")).saveAsTextFile("linesB.txt")

如果有这样的话会很好:

    val resultMap = logData.map(line => if line.contains("a") ("a", line) else if line.contains("b") ("b", line) else (" - ", line)
    resultMap.writeByKey("a", "linesA.txt") 
    resultMap.writeByKey("b", "linesB.txt")

这样的事吗?

2 个答案:

答案 0 :(得分:4)

也许这样的事情会起作用:

def singlePassMultiFilter[T](
      rdd: RDD[T],
      f1: T => Boolean,
      f2: T => Boolean,
      level: StorageLevel = StorageLevel.MEMORY_ONLY
  ): (RDD[T], RDD[T], Boolean => Unit) = {
  val tempRDD = rdd mapPartitions { iter =>
    val abuf1 = ArrayBuffer.empty[T]
    val abuf2 = ArrayBuffer.empty[T]
    for (x <- iter) {
      if (f1(x)) abuf1 += x
      if (f2(x)) abuf2 += x
    }
    Iterator.single((abuf1, abuf2))
  }
  tempRDD.persist(level)
  val rdd1 = tempRDD.flatMap(_._1)
  val rdd2 = tempRDD.flatMap(_._2)
  (rdd1, rdd2, (blocking: Boolean) => tempRDD.unpersist(blocking))
}

请注意,对rdd1(resp。rdd2)调用的操作将导致计算并保留tempRDD。这实际上相当于计算rdd2(分别为rdd1),因为flatMaprdd1定义中rdd2的开销是我认为的,可以忽略不计。

你可以这样使用singlePassMultiFitler

val (rdd1, rdd2, cleanUp) = singlePassMultiFilter(rdd, f1, f2)
rdd1.persist()    //I'm going to need `rdd1` more later...
println(rdd1.count)  
println(rdd2.count) 
cleanUp(true)     //I'm done with `rdd2` and `rdd1` has been persisted so free stuff up...
println(rdd1.distinct.count)

显然,这可以扩展到任意数量的过滤器,过滤器集合等。

答案 1 :(得分:3)

看一下以下问题。

Write to multiple outputs by key Spark - one Spark job

您可以使用以下功能flatMap RDD,然后在密钥上执行groupBy

def multiFilter(words:List[String], line:String) = for { word <- words; if line.contains(word) } yield { (word,line) }
val filterWords = List("a","b")
val filteredRDD = logData.flatMap( line => multiFilter(filterWords, line) ) 
val groupedRDD = filteredRDD.groupBy(_._1) 

但是根据输入RDD的大小,您可能会看到或不会看到任何性能提升,因为任何groupBy操作都会涉及到混乱。

另一方面,如果Spark集群中有足够的内存,则可以缓存输入RDD,因此运行多个过滤操作可能并不像您想象的那么昂贵。