了解SparkSQL及其对分区的使用

时间:2016-09-16 19:17:47

标签: apache-spark apache-spark-sql

我正在尝试评估Spark SQL的一些数据操作查询。我对此感兴趣的场景:

table1: key, value1, value2
table2: key, value3, value4

create table table3 as
select * from table1 join table2 on table1.key = table2.key

听起来我应该能够创建table1和table2 RDD(但我没有在文档中看到一个非常明显的例子)。 但更大的问题是 - 如果我已经通过密钥成功分区了2个表RDD,然后再将它们与Spark SQL连接起来,那么它是否足够智能以利用分区?如果我因为该连接而创建一个新的RDD,它是否也会被分区?换句话说,它会完全没有洗牌吗? 我非常感谢有关这些主题的文档和示例的指示。

1 个答案:

答案 0 :(得分:4)

如果您的意思是RDDsDatasets之间的转换,那么这两个问题的答案都是否定的。

RDD分区仅针对RDD[(T, U)]定义,并且会在RDD转换为Dataset后丢失。在某些情况下,您可以使每个现有数据布局受益,但join不是其中之一,RDDsDatasets使用不同的散列技术(标准hashCode和{ {1}}。您当然可以通过定义自定义分区MurmurHash来模仿后者,但实际上并非如此。

同样,当RDD转换为Dataset时,有关分区的信息会丢失。

您可以使用RDD分区来优化Dataset。例如,如果表已经预分区:

joins

基于val n: Int = ??? val df1 = Seq( ("key1", "val1", "val2"), ("key2", "val3", "val4") ).toDF("key", "val1", "val2").repartition(n, $"key").cache val df2 = Seq( ("key1", "val5", "val6"), ("key2", "val7", "val8") ).toDF("key", "val3", "val4").repartition(n, $"key").cache 的后续join不需要额外的兑换。

key
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1

df1.explain
// == Physical Plan ==
// InMemoryTableScan [key#171, val1#172, val2#173]
//    +- InMemoryRelation [key#171, val1#172, val2#173], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
//          +- Exchange hashpartitioning(key#171, 3)
//             +- LocalTableScan [key#171, val1#172, val2#173]
df2.explain
// == Physical Plan ==
// InMemoryTableScan [key#201, val3#202, val4#203]
//    +- InMemoryRelation [key#201, val3#202, val4#203], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
//          +- Exchange hashpartitioning(key#201, 3)
//             +- LocalTableScan [key#201, val3#202, val4#203]
// 

显然,我们并没有真正从单一联盟中获益。因此,只有将一个表用于多个df1.join(df3, Seq("key")).explain // == Physical Plan == // *Project [key#171, val1#172, val2#173, val5#232, val6#233] // +- *SortMergeJoin [key#171], [key#231], Inner // :- *Sort [key#171 ASC], false, 0 // : +- *Filter isnotnull(key#171) // : +- InMemoryTableScan [key#171, val1#172, val2#173], [isnotnull(key#171)] // : +- InMemoryRelation [key#171, val1#172, val2#173], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas) // : +- Exchange hashpartitioning(key#171, 3) // : +- LocalTableScan [key#171, val1#172, val2#173] // +- *Sort [key#231 ASC], false, 0 // +- *Filter isnotnull(key#231) // +- InMemoryTableScan [key#231, val5#232, val6#233], [isnotnull(key#231)] // +- InMemoryRelation [key#231, val5#232, val6#233], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas) // +- Exchange hashpartitioning(key#231, 3) // +- LocalTableScan [key#231, val5#232, val6#233] 时才有意义。

同样,Spark可以从joins创建的分区中受益,因此如果我们想要执行另一个join

join

我们将受益于第一个操作(注释val df3 = Seq( ("key1", "val9", "val10"), ("key2", "val11", "val12") ).toDF("key", "val5", "val6") df1.join(df3, Seq("key")).join(df3, Seq("key")) )创建的结构:

ReusedExchange