在spark

时间:2015-08-27 17:00:41

标签: join apache-spark partitioning

我有以下数据集:

Dataset 1:                 Dataset 2:                   Dataset 3:
id  field1                 l_id    r_id                 id field2

以下是他们的尺码: 数据集1:20G 数据集2:5T 数据集3:20G

目标: 我想在id字段(带有来自Dataset1的id的l_id和带有来自Dataset 3的id的r_id)上加入所有这些数据集,最终数据集如下所示:

l_id     r_id     field1      field2

我当前的方法: 加入Dataset1和Dataset2(在id和l_id上)生成(l_id r_id field1)然后将其与Dataset3(在r_id和id上)连接以生成(l_id r_id field1 field2)我假设spark自动使用散列分区器查看字段加入。 但是,这种方法会导致其中一个执行程序因磁盘空间不足而耗尽磁盘空间。

您能否建议我如何加入这些数据集?我的理解是,spark默认使用散列分区程序,查看正确连接的列?或者我是否必须先手动分区数据然后执行连接?

请注意,广播Dataset1 / 2不是一个选项,因为它们太大了,未来可能会变得更大。此外,所有数据集都是非键值RDD,并且包含的​​字段多于此处列出的字段。所以我不确定默认分区的工作原理以及如何配置自定义分区程序。

感谢。

更新1

我正在使用hive SQL来执行设置为33000的spark.sql.shuffle.partitions的所有连接以及以下配置:

sparkConf.set("spark.akka.frameSize", "500")
sparkConf.set("spark.storage.memoryFraction", "0.2")
sparkConf.set("spark.network.timeout", "1200")
sparkConf.set("spark.yarn.scheduler.heartbeat.interval-ms", "10000")
sparkConf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
sparkConf.set("spark.driver.maxResultSize", "0")
sparkConf.set("spark.shuffle.consolidateFiles", "true")

我也可以控制所有这些数据集的生成方式。他们似乎都没有设置分区器(通过查看rdd.partitioner),我在SQLContext中看不到任何API,这将允许我在创建数据框时配置分区器。

我正在使用scala和Spark 1.3

1 个答案:

答案 0 :(得分:0)

您数据的分区取决于RDD的来源。您不需要手动重新分区数据。但是,如果您对数据进行重新分区以使它们具有相同的分区,那么加入(& cogrouping)将导致一个狭窄的转换,而不是作为连接的一部分进行随机播放。请注意,在较新版本的Spark(1.2+)中,默认shuffle现在是基于排序的shuffle而不是基于散列的shuffle。

很难说如何在没有代码的情况下更改联接日志存在(也许有用的也可能知道ID的分布是什么样的。)

如果存在不平衡数据问题,您可以尝试增加分区数量(作为输入和输出)。一种可能是您的临时空间太小,您可以将Spark配置为使用不同的目录进行临时存储spark.local.dir。如果您的对象是kyro可序列化的(或者如果您有时间添加它),您可能还需要查看更改spark.serializer,因为不同的序列化可以占用更少的空间。

虽然与作业完成没有直接关系,但您可能还希望增加spark.shuffle.memoryFraction并减少spark.storage.memoryFraction,以便减少随机播放期间所需的磁盘溢出量。

如果您的结构数据略有不同,可以选择使用支持同时加入多个RDD的cogroup,但这要求所有密钥都相同。

注意:这一切都假设您正在使用原始Spark而不是Spark SQL。要调优Spark SQL连接,请查看https://spark.apache.org/docs/latest/sql-programming-guide.html(特别是考虑调整spark.sql.shuffle.partitions)。

希望这有帮助。