Q火花计数与拍摄和长度

我用的是当运行齐柏林飞艇笔记本时,不明白两种操作在Spark中的区别。一个操作需要大量的计算时间,第二个操作立即执行。有人能给我解释一下两种操作的区别吗:

      
2019-02-19 13:32:41  

A回答

  • 1

    您看到的是(类似于转换的操作)和(类似于操作的操作)的实现之间的区别。然而,时间上的差异是非常误导人的,在一般情况下,这是不可能的。

    首先,让我们创建一个mcve

    确保我们从干净的板开始:

    调用:

    并查看执行计划(来自spark ui):

    核心组件是

    ,这表明我们可以期待多个阶段的广泛操作。我们可以看到一个作业

    有两个阶段

    有八个

    任务现在,让我们将它与

    < PRE> >/PRE> > P>生成如下的

    < Prime= =Lang-Nop-TrimePrimabrime>>/Prime>

    。同时,全局和局部的限制仍然存在,中间没有交换。因此,我们可以期待一个单一阶段的行动。请注意,Planner将限制范围缩小到了更严格的值。

    正如预期的那样,我们看到一个新的作业:

    它只生成一个阶段:

    只有一个任务prettyprint override>

    这对我们意味着什么?

    • 在spark使用宽变换的情况下,实际上应用于每个分区,并将部分结果洗牌以执行。
    • 在spark使用窄变换且仅在第一个分区上求值的情况下。

    显然后一种方法在第一个分区中的值数低于请求的限制时不起作用。

    在这种情况下,第一个将使用与之前完全相同的逻辑(我鼓励您从经验上确认这一点),但将采取相当不同的路径。到目前为止,我们只触发了两个作业:

    如果现在执行,您将看到它还需要3个作业:

    那么这里发生了什么?如前所述,计算单个分区不足以满足一般情况下的限制。在这种情况下,spark会对分区进行迭代计算,直到满意为止,每次迭代中使用的分区数都会增加。

    这种策略可能会对性能产生重大影响。单独启动spark作业并不便宜,而且在某些情况下,当上游对象是广泛转换的结果时,事情会变得非常糟糕(在最佳情况下,您可以读取shuffle文件,但如果这些文件由于某种原因丢失,spark可能会被迫重新执行所有依赖项)。

    总结一下:

    • 是一个操作,在上游过程狭窄的特定情况下可能会短路,并且可以使用前几个分区来满足需要。
    • 是一个转换,并且总是计算所有值,因为没有迭代转义填充。

    虽然在特定情况下一个可以比另一个表现得更好,但它们不可交换,也不能保证总体性能更好。

    2019-02-18 21:40:09  Feb 18 at 11:39
    • 感谢您的完整回答! – DmitryZyr Feb 18 at 13:00