SparkSQL PostgresQL数据帧分区

时间:2015-07-10 13:17:47

标签: postgresql apache-spark apache-spark-sql partition

我有一个非常简单的SparkSQL连接到Postgres数据库的设置,我试图从表中获取一个DataFrame,Dataframe有X个分区(比方说2)。代码如下:

Map<String, String> options = new HashMap<String, String>();
options.put("url", DB_URL);
options.put("driver", POSTGRES_DRIVER);
options.put("dbtable", "select ID, OTHER from TABLE limit 1000");
options.put("partitionColumn", "ID");
options.put("lowerBound", "100");
options.put("upperBound", "500");
options.put("numPartitions","2");
DataFrame housingDataFrame = sqlContext.read().format("jdbc").options(options).load();

由于某种原因,DataFrame的一个分区几乎包含所有行。

我能理解lowerBound/upperBound是用来微调这个的参数。在SparkSQL的文档(Spark 1.4.0 - spark-sql_2.11)中,它表示它们用于定义步幅,而不是用于过滤/范围分区列。但这提出了几个问题:

  1. 步幅是每个执行者(分区)查询数据库的频率(每个查询返回的元素数)?
  2. 如果没有,这些参数的目的是什么,它们依赖于什么?如何以稳定的方式平衡我的DataFrame分区(不要求所有分区包含相同数量的元素,只是存在均衡 - 例如2个分区100个元素55 / 45,60 / 40甚至65/35都可以)
  3. 似乎无法找到这些问题的明确答案,并且想知道是否有些人可以为我清楚这一点,因为现在正在影响我的群集性能,当处理X万行和所有重提升到一个执行者。

    欢呼并感谢您的时间。

3 个答案:

答案 0 :(得分:5)

基本上,下限和上限以及分区数用于计算每个并行任务的增量或拆分。

我们假设该表有分区栏&#34;年&#34;,并且有2006年至2016年的数据。

如果您将分区数定义为10,使用下限2006和更高的界限2016,您将使每个任务获取其自己年份的数据 - 理想情况。

即使您错误地指定了下限和/或上限,例如设置lower = 0和upper = 2016,数据传输会出现偏差,但是,你不会失去&#34;或者无法检索任何数据,因为:

第一项任务将获取年份数据&lt; 0

第二项任务将获取0到2016/10之间的年度数据。

第三项任务将获取2016/10和2 * 2016/10之间的年度数据。

...

最后一项任务将具有年度 - > 2016年的条件。

吨。

答案 1 :(得分:2)

下限确实用于分区列;请参阅此代码(撰写本文时的当前版本):

https://github.com/apache/spark/blob/40ed2af587cedadc6e5249031857a922b3b234ca/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JDBCRelation.scala

函数columnPartition包含分区逻辑的代码以及下限/上限的使用。

答案 2 :(得分:0)

目前已确定

下限和上限执行他们在之前答案中所做的操作。对此的后续操作将是如何在不查看最小最大值或数据严重偏差的情况下平衡分区间的数据。

如果您的数据库支持&#34; hash&#34;功能,它可以做到这一点。

partitionColumn =&#34; hash(column_name)%num_partitions&#34;

numPartitions = 10 //无论你想要什么

lowerBound = 0

upperBound = numPartitions

只要模数运算在[0,numPartitions]

上返回均匀分布,这将起作用