我的理解是,如果我有一个数据帧,如果我缓存()它并触发像df.take(1)
或df.count()这样的操作,它应该计算数据帧并将其保存在内存中,并且每当缓存数据帧时在程序中调用它已使用已从缓存中计算出的数据帧。
但这不是我的计划如何运作。
我有一个类似于下面的数据框,我正在缓存它,然后立即执行df.count
操作。
val df = inputDataFrame.select().where().withColumn("newcol" , "").cache()
df.count
当我运行程序时。在Spark UI中,我看到第一行运行4分钟 当谈到第二行时,它再次运行4分钟基本上第一行重新计算两次?
当第二行触发时,第一行不应该计算和缓存吗?
如何解决此问题。我被卡住了,请指教。
答案 0 :(得分:0)
我的理解是,如果我有一个数据帧,如果我缓存()它并触发像df.take(1)或df.count()这样的动作,它应该计算数据帧并将其保存在内存中,
这是不正确的。简单的cache
和count
(take
也不适用于RDD)是RDD的有效方法,但Datasets
的情况并非如此,它使用更高级的优化。查询:
df.select(...).where(...).withColumn("newcol" , "").count()
任何未在where
子句中使用的列都可以忽略。
有一个重要的discussion on the developer list和引用Sean Owen
我认为正确的答案是“不要这样做”但如果你真的不得不触发数据集操作,那么每个分区什么都不做。我认为这样会更可靠,因为必须计算整个分区以使其在实践中可用。或者,尽可能地遍历每个元素。
转换为代码:
df.foreach(_ => ())
有
df.registerAsTempTable("df")
sqlContext.sql("CACHE TABLE df")
这是热切但不再(Spark 2和前进)记录,应该避免。
答案 1 :(得分:0)
不,如果您在DataFrame上拨打cache
,此时此时尚未缓存,则仅标记为""标记为"用于潜在的未来缓存。实际缓存仅在稍后执行操作时完成。您还可以在"存储"
代码中的另一个问题是DataFrame上的count
不会计算整个DataFrame,因为并非需要为此计算所有列。您可以使用df.rdd.count()
强制进行整个演绎(请参阅How to force DataFrame evaluation in Spark)。
问题是为什么你的第一次操作需要这么长时间,即使没有调用任何动作。我认为这与调用缓存时计算的缓存逻辑(例如大小估计等)有关(参见例如Why is rdd.map(identity).cache slow when rdd items are big?)