在持久的RDD上执行多个操作时,如何缓存RDD

时间:2018-07-31 18:38:49

标签: scala apache-spark caching rdd

val logList: RDD[String] = ...
val errorLogs = logList.filter(_.contains("Error")).persist()
//first action   
val first100 = errorLogs.take(100)
//second action
val count = errorLogs.count 

在这种情况下如何继续工作?在以下代码的情况下

val errorLogs = logList.filter(_.contains("Error")).take(100)

Spark不会扫描所有日志,因为Spark知道我们只对100行日志感兴趣。但是,当我们缓存该RDD并对其调用多个动作时,将会发生什么情况,第一个动作只需要很少的记录,而后一个则需要转换整个RDD。

在调用第一个操作时会缓存记录吗?还是在调用第一个操作时仅缓存第一个操作所需的部分记录?

2 个答案:

答案 0 :(得分:6)

在这种情况下,Spark将仅缓存收集100条记录所需的最小分区数(由于实施,实际数量可能会更高)。

保证只有第二个可以缓存所有记录。

答案 1 :(得分:2)

cache的工作方式

  • cachepersist是惰性的-如果未持久化标记为缓存数据的RDD上的任何操作,则不会持续。同样,如果未评估分区,则数据不会持久保存。
  • cache保留整个分区。它不能保留单个记录或部分分区。如果将数据标记为要缓存,并且至少对分区进行了部分评估,Spark将对其进行完整评估并尝试保留。

limit的工作方式

  • 第一个limit评估第一个分区。如果可以从第一个分区收集到限制要求的所有记录,则作业完成。
  • 如果不是,那么Spark将增加spark.rdd.limit.scaleUpFactor要评估的分区数。如果可以从这些分区中收集到限制所需的所有记录,则作业完成。否则,将重复此步骤。

这意味着:

  • val first100 = errorLogs.take(100)将至少缓存第一个分区。如果第一个分区不包含100条记录,它将评估并缓存后续分区,直到达到100条记录或评估完整的数据集。
  • val count = errorLogs.count将评估所有分区,并在可能的情况下缓存其余分区。
  • val errorLogs = logList.filter(_.contains("Error")).take(100)的工作原理与errorLogs.take(100)几乎完全相同。 filter的唯一影响是limit可能必须评估更多数据。如果所有行都包含Error,则结果与第一步相同。

    如果此操作在前两个步骤之后运行,并且数据已完全缓存并且尚未被逐出,它将使用缓存中的数据。