我有以下数据集:
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
答案 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
)。
希望这有帮助。