Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 意外的火花缓存行为_Scala_Apache Spark_Rdd - Fatal编程技术网

Scala 意外的火花缓存行为

Scala 意外的火花缓存行为,scala,apache-spark,rdd,Scala,Apache Spark,Rdd,我有一个spark程序,基本上可以做到这一点: def foo(a: RDD[...], b: RDD[...]) = { val c = a.map(...) c.persist(StorageLevel.MEMORY_ONLY_SER) var current = b for (_ <- 1 to 10) { val next = some_other_rdd_ops(c, current) next.persist(StorageLevel.MEMOR

我有一个spark程序,基本上可以做到这一点:

def foo(a: RDD[...], b: RDD[...]) = {
  val c = a.map(...)
  c.persist(StorageLevel.MEMORY_ONLY_SER)
  var current = b
  for (_ <- 1 to 10) {
    val next = some_other_rdd_ops(c, current)
    next.persist(StorageLevel.MEMORY_ONLY)
    current.unpersist()
    current = next
  }
  current.saveAsTextFile(...)
}

要点第31-42行对应于上述简化版本。我得到了对应于第31行的10个阶段,而我只希望得到1个阶段。

缓存不会减少阶段,只是不会每次都重新计算阶段

在第一次迭代中,在stage的“输入大小”中,您可以看到数据来自Hadoop,并且它读取shuffle输入。在随后的迭代中,数据来自内存,不再进行无序输入。此外,执行时间大大缩短


每当需要写入洗牌时,就会创建新的映射阶段,例如当分区发生变化时,在您的例子中,向RDD添加一个键。

这里的问题是调用
缓存是懒惰的。在触发操作并计算RDD之前,不会缓存任何内容。调用所做的只是在RDD中设置一个标志,以指示在计算时应该缓存它

然而,Unpersist立即生效。它清除指示应该缓存RDD的标志,并开始从缓存中清除数据。由于在应用程序的末尾只有一个操作,这意味着在计算任何RDD时,Spark都不会看到任何RDD应该被持久化

我同意这是一种令人惊讶的行为。一些Spark库(包括GraphX中的PageRank实现)解决这一问题的方法是显式地具体化调用
缓存
取消持久化
之间的每个RDD。例如,在您的情况下,您可以执行以下操作:

def foo(a: RDD[...], b: RDD[...]) = {
  val c = a.map(...)
  c.persist(StorageLevel.MEMORY_ONLY_SER)
  var current = b
  for (_ <- 1 to 10) {
    val next = some_other_rdd_ops(c, current)
    next.persist(StorageLevel.MEMORY_ONLY)
    next.foreachPartition(x => {}) // materialize before unpersisting
    current.unpersist()
    current = next
  }
  current.saveAsTextFile(...)
}
def foo(a:RDD[…],b:RDD[…])={
val c=a.map(…)
c、 持久化(存储级别。仅内存)
无功电流=b
for({})//在取消持久化之前具体化
current.unpersist()
当前=下一个
}
当前.saveAsTextFile(…)
}

我认为你的期望是对的。也许代码有点可疑?你能提供一个我们可以重现这个问题的例子吗?一种可能的解释是,当你不断地把东西放进缓存时,它会推出
c
。但我不确定情况是否如此。Daniel猜测缓存被逐出是正确的。另外,一些其他的操作对我们来说是一个黑盒子…所以可能会做一些意想不到的事情。我将进一步研究您的
current.unpersist()
语句。你确定c永远不会成为最新版本吗?@marios,是的,我确定。c和current有不同的类型@JustinPihony,其他一些rdd操作是:
c.join(current.map(…).aggregateByKey(…).mapValues(…)
。没有persist/unpersist、collect、saveToTextFile等@DanielDarabos当然,我添加了一个完全可执行的示例来重现这一点。对不起,这有点复杂;这就是我最初发布简化版的原因。
def foo(a: RDD[...], b: RDD[...]) = {
  val c = a.map(...)
  c.persist(StorageLevel.MEMORY_ONLY_SER)
  var current = b
  for (_ <- 1 to 10) {
    val next = some_other_rdd_ops(c, current)
    next.persist(StorageLevel.MEMORY_ONLY)
    next.foreachPartition(x => {}) // materialize before unpersisting
    current.unpersist()
    current = next
  }
  current.saveAsTextFile(...)
}