Spark加入最佳比赛效率问题

时间:2019-10-14 10:13:17

标签: apache-spark join pyspark

我有2个数据框:

  • df_1拥有约5亿条记录和约100列
  • df_2拥有约5000万条记录和4列

我需要将df_1df_2的联接留在其中两​​列完全匹配,而第三列最佳匹配。最好的匹配,我的意思是从左到右有一个多对多的关系,但是我只想在长度方面在右侧得到最好的匹配。

例如

# df_1
col1    col2    col3
---------------------------
a       b       abcde
# df_2
col1    col2    col3    col4
-------------------------------
a       b       a       90
a       b       ab      100
a       b       abc     150
a       c       abc     90

因此,当我完全匹配col1col2并与包含的字符串的最佳匹配项的col3完全匹配时,联接的期望结果是:

col1    col2    col3    col4
-------------------------------
a       b       abcde   150

有些要害我的地方:

  • 左侧col3的长度通常在10到15个字符之间,在右侧可以从1个字符变为9个字符
  • df_1df_2都类似地偏向col3

虽然我能做到这一点,但是却得到了糟糕的表现

我尝试了以下解决方案,但仍无所获:

  • 广播df_2(因为广播太大而无法广播)
  • col1col1上完全连接,并在like上使用col3(很糟糕)
  • 展开col3df_2上的值以尝试解决倾斜(改进但仍然很慢)
  • 持久化数据并在右侧的每个长度中循环,并完全按照col1col2col3的串联连接(其中左侧的串联是一个col3的子字符串)(改进但仍然很慢)

使用spark进行连接的最有效方法是什么?

1 个答案:

答案 0 :(得分:0)

一个更好的选择是在加入之前减小数据大小(我们无法消除加入)。我们可以减少如下:

首先,加载数据

scala> import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.expressions.Window

scala> import org.apache.spark.sql.functions._
import org.apache.spark.sql.functions._

scala> df1.show
+---+---+-----+
| c1| c2|   c3|
+---+---+-----+
|  a|  b|abcde|
|  c|  d|   fd|
+---+---+-----+

scala> df2.show
+---+---+----+---+
| c1| c2|  c3| c4|
+---+---+----+---+
|  a|  b|   a| 90|
|  a|  b| abd|100|
|  a|  b|abcd|150|
|  c|  d|wewe| 79|
+---+---+----+---+

现在,我们需要使用窗口函数并找出两列的最大值

,以在连接之前减小df2的大小(这将减少连接所需的时间,因为数据大小较小)。
scala> df2.withColumn("len", length($"c3")).withColumn("res", row_number().over(wind1)).filter($"res" === 1).withColumn("res2", row_number().over(wind2)).filter($"res2"=== 1).select("c1", "c2", "c3", "c4").show()
+---+---+----+---+
| c1| c2|  c3| c4|
+---+---+----+---+
|  c|  d|wewe| 79|
|  a|  b|abcd|150|
+---+---+----+---+

可尝试的东西:

1>您可以加入这个简化的数据框并应用您正在使用的逻辑

2>尝试进行并集df1.withColumn("c4", lit(0)).union(df2),然后应用上述逻辑。

希望这会有所帮助