Apache Spark,范围联接,数据偏斜和性能

时间:2019-04-01 17:51:47

标签: scala apache-spark apache-spark-sql

我有以下Apache Spark SQL连接谓词:

t1.field1 = t2.field1 and t2.start_date <= t1.event_date and t1.event_date < t2.end_date

数据:

t1 DataFrame have over 50 millions rows
t2 DataFrame have over 2 millions rows

t1.field1 DataFrame中的几乎所有t1字段都具有相同的值(null)。

目前,Spark群集在单个任务上挂起10分钟以上,以执行此连接,并且由于数据倾斜。在这个时间点上,只有一个工人和该工人上的一项任务起作用。其他所有9名工人都闲着。如何改善这种连接以便将负载从这一特定任务分配到整个Spark集群?

3 个答案:

答案 0 :(得分:2)

我假设您正在进行内部联接。

可以按照以下步骤优化连接- 1.加入之前,我们可以根据最小或最大的start_date,event_date,end_date筛选出t1和t2。它将减少行数。

  1. 检查t2数据集的field1是否为空值,如果没有,则可以基于notNull条件过滤连接t1数据集。它将减小t1的大小

  2. 如果您的工作仅获得很少的执行程序,那么执行的分区数就会更少。只需对数据集重新分区,设置一个最佳数量,这样就不会出现大量分区,反之亦然。

  3. 您可以通过查看任务执行时间来检查分区是否正确发生(没有偏斜),应该类似。

  4. 检查执行程序的内存中是否可以容纳较小的数据集,可以使用broadcast_join。

您可能想读-https://github.com/vaquarkhan/Apache-Kafka-poc-and-notes/wiki/Apache-Spark-Join-guidelines-and-Performance-tuning

答案 1 :(得分:2)

如果 t1 中的几乎所有行都具有 t1.field1 = null,并且 event_date 行是数字(或者您将其转换为时间戳),您可以先使用 Apache DataFu 进行范围连接,然后过滤掉 t1.field1 != t2.field1 之后的行。

范围连接代码如下所示:

t1.field1 = t2.field1 和 t2.start_date <= t1.event_date 和 t1.event_date

t1.joinWithRange("event_date", t2, "start_date", "end_date", 10)

最后一个参数 - 10 - 是减少因子。正如 Raphael Roth 在他的回答中所建议的那样,这会进行分桶。

您可以在 the blog post introducing DataFu-Spark 中看到这种范围连接的示例。

完全披露 - 我是 DataFu 的成员并撰写了博文。

答案 2 :(得分:1)

我假设spark已经在t1.field1上推送了非null过滤器,您可以在说明计划中进行验证。

我宁愿尝试创建一个可以用作等联接条件的附加属性,例如通过桶装。例如,您可以创建一个month属性。为此,您需要在months中枚举t2,这通常是使用UDF完成的。有关示例,请参见此SO问题:How to improve broadcast Join speed with between condition in Spark