在CouchDB和类似Incoop的系统设计中,有一个名为“Incremental MapReduce”的概念,其中保存了以前执行MapReduce算法的结果,并用于跳过尚未更改的输入数据部分。
假设我有100万行分为20个分区。如果我对这些数据运行一个简单的MapReduce,我可以缓存/存储减少每个单独分区的结果,然后再将它们组合并再次减少以产生最终结果。如果我只更改第19个分区中的数据,那么我只需要运行map&减少更改的数据部分的步骤,然后将新结果与未更改的分区中保存的reduce结果组合以获得更新的结果。使用这种捕获方法,我可以跳过近95%的工作来重新运行这个假设数据集上的MapReduce作业。
有没有什么好方法可以将此模式应用于Spark?我知道我可以编写自己的工具来将输入数据拆分成分区,检查我之前是否已经处理过这些分区,如果有的话,从缓存中加载它们,然后运行最终的reduce来将所有分区连接在一起。但是,我怀疑有一种更简单的方法可以解决这个问题。
我已经在Spark Streaming中尝试了检查点,并且能够在重新启动之间存储结果,这几乎就是我正在寻找的,但我想在流媒体工作之外执行此操作。
RDD缓存/持久化/检查点几乎看起来像我可以构建的东西 - 它可以很容易地保持中间计算并在以后引用它们,但我认为一旦SparkContext停止,缓存的RDD总是被删除,即使它们'坚持到磁盘。因此,缓存不适用于在重新启动之间存储结果。此外,我不确定在启动新的SparkContext时是否应该加载检查点RDD ...它们似乎存储在特定于SparkContext的单个实例的UUID in the checkpoint directory下。
答案 0 :(得分:1)
article建议的两个用例(增量日志处理和增量查询处理)通常可以通过Spark Streaming解决。
我们的想法是使用DStreams抽象进行增量更新。然后,您可以处理新数据,并使用基于时间窗口的处理或使用任意有状态操作作为Structured Stream Processing的一部分,将其与先前的计算结合起来。计算结果可以稍后转储到某种外部接收器(如数据库或文件系统),或者它们可以作为SQL表公开。
如果您没有构建在线数据处理系统,也可以使用常规Spark。这只是增量更新如何进入流程以及如何保存中间状态的问题。例如,增量更新可以出现在分布式文件系统的某个路径下,而包含先前计算的中间状态可以再次转储到同一文件系统中。