在测试生产用例时,我已经创建并保存(使用Hive Metastore)这样的表:
table1:
fields: key1, key2, value1
sortedBy key1,key2
bucketBy: key1, 100 buckets
table2:
fields: key1, key2, value2
sortedBy: key1,key2
bucketBy: key1, 100 buckets
我正在运行这样的查询(使用伪代码)
table1.join(table2, [“key1”, “key2”])
.groupBy(“value2”)
.countUnique(“key1”)
常识说,这种连接应该简单地通过没有任何交换的排序合并连接来完成;但是spark会进行交流然后加入。
尽管对于这个特定用例,由于我需要按key1进行存储的其他一些用例,我还是可以对两个键进行存储。而当我使用这样的单个键进行(简单)连接时:
table1.join(table2, [“key1”])
它按预期工作(即不进行任何交换的排序合并联接)。
现在,如果要过滤,我在这些表上有一个优化的联接:
table1.join(table2, [“key1”])
.filter(table1.col(“key2”) == table2.col(“key2”))
它恢复为交换,然后加入。
当连接键是bucketBy键的超集时,如何说服火花不要进行交换?
答案 0 :(得分:1)
基于一些研究和探索,这似乎是最不容易破解的解决方案:
基于此示例:
table1.join(table2, [“key1”])
.filter(table1.col(“key2”) == table2.col(“key2”))
代替使用Spark中的equalTo (==)
,实现自定义MyEqualTo
(通过委托spark EqualTo
实现很好)似乎可以解决此问题。这样,spark不会优化(!)联接,它只会将过滤器拉到SortMergeJoin中。
类似地,联接条件也可以这样形成:
(table1.col(“key1”) == table2.col(“key1”)) AND
table1.col(“key2”).myEqualTo(table2.col(“key2”))
答案 1 :(得分:0)
org.apache.spark.sql.catalyst.optimizer.PushPredicateThroughJoin
是优化程序规则,用于通过谓词推送谓词。 ~~
我们可以从优化程序规则中排除该规则。这样,我们无需对用户代码进行任何更改。
要排除的情况,我们可以执行以下操作之一
1. --conf spark.sql.optimizer.excludedRules=org.apache.spark.sql.catalyst.optimizer.PushPredicateThroughJoin
。
2.将属性添加到spark-defaults .conf。
3.将set spark.sql.optimizer.excludedRules=org.apache.spark.sql.catalyst.optimizer.PushPredicateThroughJoin
添加到用户代码中。
再次,这再次是黑客。。
理想情况下,应该通过连接将过滤器下推,这样可以减少要连接的行数
更新 :。
1.关于下推我是错的。由于谓词具有两个表中的列,因此将没有过滤器下推。
2. 为什么当 where 子句具有“非相等”谓词时,SortMergeJoin(SMJ)为什么不添加其他交换?
这是因为SMJ只能将基于相等性的谓词视为连接条件org.apache.spark.sql.catalyst.planning.ExtractEquiJoinKeys#unapply
负责添加交换的确保需求看到SMJ没有新的加入条件,并且输出分配已经满足。
代码:org.apache.spark.sql.execution.exchange.EnsureRequirements#ensureDistributionAndOrdering。
3. 哪种方法有效?添加一个等于或大于等于谓词的谓词的UDF?。
为了对此进行评估,我使用来检查生成的代码,
val df = spark.sql(<joinquery>)
df.queryExecution.debug.codegen
a。 UDF等于-涉及虚拟函数调用的额外开销。
b。小于和大于的组合-没有虚拟函数调用。一旦找到连接的行(使用key1),代码就会一个接一个地检查其他谓词。
根据上述3中的观察,使用基于非等式的谓词似乎更有效。
答案 2 :(得分:0)
**根据您的伪代码**
table1.join(table2,[“ key1”,“ key2”]) .groupBy(“ value2”) .countUnique(“ key1”)
我想解决办法是
第一步,只需连接表并获取数据框。
df = table1.join(table2, [“key1”, “key2”])
然后分组并进行不同的计数
df.select(“value2”,“key1”).distinct().groupBy(“value2”,“key1”).count().show()
答案 3 :(得分:0)
我正面临着同样的问题。 看来PR已完成,正好解决了这个问题
(PR)https://github.com/apache/spark/pull/19054
(吉拉票)https://issues.apache.org/jira/browse/SPARK-18067
但是我希望它已经被包含在内(我正在使用Spark 3.0.0,并且问题仍然存在,而票证已于2019年5月21日解决,距离Spark3发布已经一年多了。) >
感谢使用不等式运算符的“ hack”,虽然感觉不太好,但这是一个简单的解决方法。我还将尝试使用PR中的解决方案来修补我的spark版本,但是如果我要共享我的代码,这将不太可持续/不可再现。