Spark SQL深入分析之图解Aggregation策略工作流程

前言

学习完上一篇文章:学习Spark SQL一定要弄懂的Spark Planner工作原理后,相信大家对SparkPlanner的原理有了大致的了解,接下来的几篇文章将对一些重要的策略进行更深入的挖掘,首先从Aggregation策略开始。

Aggregation策略根据聚合表达式的类型来规划逻辑聚合运算符的物理执行计划。Catalyst询计划器定义了PhysicalAggregation模式,它从逻辑计划中提取聚合表达式(AggregateExpression类型)。Aggregation策略在逻辑计划中查找PhysicalAggregation模式,并根据从PhysicalAggregation模式中提取的聚合表达式的类型选择合适的执行计划。

如下图所示,如果聚合表达式是PythonUDF的实例,将返回一个AggregateInPandasExec节点,这是用group aggregate Pandas UDF进行聚合的物理节点。AggregateInPandasExec的工作方式是与执行Pandas UDF的python工作者对话,并将结果发回给Spark executor。然后Spark executor 评估聚合后的表达式并返回结果。

如果聚合表达式是AggregateExpression类的一个实例,Aggregation策略会检查这个聚合表达式是否包含Distinct聚合函数,例如COUNT(DISTINCT name)。然后,Aggregation策略会相应地计划物理执行。

下面将详细分析without Distinct和with One Distinct聚合过程。

Aggregate without Distinct

对于不包含Distinct聚合的情况,会返回一个两阶段的聚合执行计划。以下面的查询为例,这个查询通过customer_id对订单行进行分组,并对item_id进行非区分计数聚合。

这是已优化的逻辑计划,其中包含一个聚合逻辑运算符。

这里是Spark Planner返回的物理计划。我们可以看到,两个HashAggregate操作符已经被规划好了,并且在中间添加了一个Exchange操作符(这个Exchange操作符不是由Spark Planner添加的,而是由查询执行准备阶段的EnsureRequirement规则添加的)。两个HashAggregate操作符都有相同的分组键:customer_id#6L,但是第一个HashAggregate操作符的聚合函数是item_id#7L的partial_count,并输出count#79L,而第二个HashAggregate操作符的聚合函数以第一个HashAggregate操作符的计数输出,count#79L作为输入,对其进行final_merge聚合。

上面的查询计划用下图表示能更加容易理解:

如上图所示,在第一个partial聚合阶段,RDD的每个分区都按customer_id分组,输出该分区中每个客户的item_id的数量。然后,第一个partial聚合阶段的输出将按customer_id进行shuffle,即RDD被重新分区,以便具有相同customer_id的行将被置于同一分区并在同一Spark executor中执行。第二个final聚合将每个customer的所有item_id数量加起来,并将最终结果返回给driver端。

Aggregate with One Distinct

Distinct聚合的Spark实现要复杂一些,涉及到四个聚合阶段和两个shuffle操作。让我们对之前使用的查询做两个小改动:不再使用COUNT(item_id),而是添加一个DISTINCT操作符,使其成为COUNT(DISTINCT item_id),此外,再添加另一个聚合表达式,SUM(price):

下图是Spark Planner返回的物理计划,我们可以看到,有四个HashAggregate阶段被规划:

在第一个partial聚合阶段,RDD的每个分区都是由customer_id和item_id分组的。在这个阶段,仅对每个分区中的non-distinct agg表达式(即我们例子中的SUM(price))进行聚合。

在第二个聚合阶段之前,分区将被reshuffle,以便将具有某些customer_id和item_id相同的记录放在同一个分区中。到了第二聚合阶段:Partial Merge Aggregation,将customer_id和item_id相同的所有sum(price)值加起来。

在同一分区内(第二和第三阶段之间没有reshuffle),第二阶段的输出行只按customer_id分组,并对不同的聚合(Count(item_id))和非不同的聚合(Sum(price))进行了聚合。

在第三阶段之后,第四个Final Aggregation阶段之前,又进行了一次shuffle,将具有相同customer_id的记录放入同一个分区。Final Aggregation阶段将第三阶段输出的COUNT(item_id)值相加,得到每个customer_id组的不同item_ids的数量。Final Aggregation阶段也对非独立的SUM(price)按customer_id进行了最后的聚合。

总结

本文主要通过一些简单SQL实例分析了Aggregation策略的过程,Spark SQL还提供了一些其它的聚合策略,用于不同的场景,具有不同的性能,这些聚合策略的特性将在后续的文章再进行详细解释,敬请关注。

- THE END -

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值