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。
在调用第一个操作时会缓存记录吗?还是在调用第一个操作时仅缓存第一个操作所需的部分记录?
答案 0 :(得分:6)
在这种情况下,Spark将仅缓存收集100条记录所需的最小分区数(由于实施,实际数量可能会更高)。
保证只有第二个可以缓存所有记录。
答案 1 :(得分:2)
cache
的工作方式:
cache
和persist
是惰性的-如果未持久化标记为缓存数据的RDD
上的任何操作,则不会持续。同样,如果未评估分区,则数据不会持久保存。cache
保留整个分区。它不能保留单个记录或部分分区。如果将数据标记为要缓存,并且至少对分区进行了部分评估,Spark将对其进行完整评估并尝试保留。 limit
的工作方式:
limit
评估第一个分区。如果可以从第一个分区收集到限制要求的所有记录,则作业完成。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
,则结果与第一步相同。
如果此操作在前两个步骤之后运行,并且数据已完全缓存并且尚未被逐出,它将使用缓存中的数据。