如何强制在Spark中使用全局外连接来使用Boradcast Hash Join?以下是代码段:
sparkConfiguration.set("spark.sql.autoBroadcastJoinThreshold", "1000000000")
val Result = BigTable.join(
org.apache.spark.sql.functions.broadcast(SmallTable),
Seq("X", "Y", "Z", "W", "V"),
"outer"
)
我的SmallTable的大小比上面指定的autoBroadcastJoinThreshold
小。此外,如果我使用内部,left_outer
或right_outer
联接,我会从DAG可视化中看到联接正在按预期使用BroadcastHashJoin
。
但是,当我使用“outer
”作为联接类型时,spark会因某种未知原因决定使用SortMergeJoin
。有谁知道如何解决这个问题?根据我在左外连接中看到的性能,BroadcastHashJoin
将有助于我的应用程序多次加速。
答案 0 :(得分:2)
由于某些未知原因,spark决定使用SortMergeJoin。是否 有谁知道如何解决这个问题?
原因: FullOuter(表示任何关键字outer
,full
,fullouter
)不支持广播哈希联接(也称为地图)加入)
如何证明这一点?
举个例子:
package com.examples import org.apache.log4j.{Level, Logger} import org.apache.spark.internal.Logging import org.apache.spark.sql.SparkSession import org.apache.spark.sql.functions._ /** * Join Example and some basics demonstration using sample data. * * @author : Ram Ghadiyaram */ object JoinExamples extends Logging { // switch off un necessary logs Logger.getLogger("org").setLevel(Level.OFF) val spark: SparkSession = SparkSession.builder.config("spark.master", "local").getOrCreate; case class Person(name: String, age: Int, personid: Int) case class Profile(name: String, personId: Int, profileDescription: String) /** * main * * @param args Array[String] */ def main(args: Array[String]): Unit = { spark.conf.set("spark.sql.join.preferSortMergeJoin", "false") import spark.implicits._ spark.sparkContext.getConf.getAllWithPrefix("spark.sql").foreach(x => logInfo(x.toString())) /** * create 2 dataframes here using case classes one is Person df1 and another one is profile df2 */ val df1 = spark.sqlContext.createDataFrame( spark.sparkContext.parallelize( Person("Sarath", 33, 2) :: Person("KangarooWest", 30, 2) :: Person("Ravikumar Ramasamy", 34, 5) :: Person("Ram Ghadiyaram", 42, 9) :: Person("Ravi chandra Kancharla", 43, 9) :: Nil)) val df2 = spark.sqlContext.createDataFrame( Profile("Spark", 2, "SparkSQLMaster") :: Profile("Spark", 5, "SparkGuru") :: Profile("Spark", 9, "DevHunter") :: Nil ) // you can do alias to refer column name with aliases to increase readablity val df_asPerson = df1.as("dfperson") val df_asProfile = df2.as("dfprofile") /** * * Example displays how to join them in the dataframe level * next example demonstrates using sql with createOrReplaceTempView */ val joined_df = df_asPerson.join( broadcast(df_asProfile) , col("dfperson.personid") === col("dfprofile.personid") , "outer") val joined = joined_df.select( col("dfperson.name") , col("dfperson.age") , col("dfprofile.name") , col("dfprofile.profileDescription")) joined.explain(false) // it will show which join was used joined.show } }
我尝试使用广播提示进行fullouter
加入,但框架忽略了,下面的SortMergeJoin
是解释计划。
结果:
== Physical Plan == *Project [name#4, age#5, name#11, profileDescription#13] +- SortMergeJoin [personid#6], [personid#12], FullOuter :- *Sort [personid#6 ASC NULLS FIRST], false, 0 : +- Exchange hashpartitioning(personid#6, 200) : +- *SerializeFromObject [staticinvoke(class org.apache.spark.unsafe.types.UTF8String, StringType, fromString, assertnotnull(input[0, com.examples.JoinExamples$Person, true]).name, true) AS name#4, assertnotnull(input[0, com.examples.JoinExamples$Person, true]).age AS age#5, assertnotnull(input[0, com.examples.JoinExamples$Person, true]).personid AS personid#6] : +- Scan ExternalRDDScan[obj#3] +- *Sort [personid#12 ASC NULLS FIRST], false, 0 +- Exchange hashpartitioning(personid#12, 200) +- LocalTableScan [name#11, personId#12, profileDescription#13] +--------------------+---+-----+------------------+ | name|age| name|profileDescription| +--------------------+---+-----+------------------+ | Ravikumar Ramasamy| 34|Spark| SparkGuru| | Ram Ghadiyaram| 42|Spark| DevHunter| |Ravi chandra Kanc...| 43|Spark| DevHunter| | Sarath| 33|Spark| SparkSQLMaster| | KangarooWest| 30|Spark| SparkSQLMaster| +--------------------+---+-----+------------------+
From spark 2.3 Merge-Sort join是spark中的默认连接算法。 但是,可以使用内部参数调低此值 'spark.sql.join.preferSortMergeJoin'默认为true。
除fullouter
加入之外的其他情况......如果您不想在任何情况下使用sortmergejoin,您可以设置以下属性。
sparkSession.conf.set("spark.sql.join.preferSortMergeJoin", "false")
这是您不想使用sortmergejoin
的代码SparkStrategies.scala
(which is responsible & Converts a logical plan into zero or more SparkPlans)的说明。
此属性spark.sql.join.preferSortMergeJoin
如果为true,则更喜欢通过此PREFER_SORTMERGEJOIN属性对shuffle散列连接进行排序合并连接。
设置false
意味着不能选择broadcasthashjo,它也可以是其他任何内容(例如,随机散列连接)。
以下文档位于SparkStrategies.scala
,即object JoinSelection extends Strategy with PredicateHelper ...
SQLConf.AUTO_BROADCASTJOIN_THRESHOLD
]]阈值
或者如果那一方有明确的广播提示(例如用户应用了
[[{{{}}]]函数到org.apache.spark.sql.functions.broadcast()
),然后是那边
连接将被广播,另一方将被流式传输,没有改组
执行。如果加入的双方都有资格被广播,那么随机散列连接:如果单个分区的平均大小足以构建散列表。
排序合并:如果匹配的连接键是可排序的。
答案 1 :(得分:2)
广播加入不支持完全外连接。它仅支持以下类型:
InnerLike | LeftOuter | LeftSemi | LeftAnti |存在加入| RightOuter
有关详细信息,请参阅JoinStrategy。