【问题标题】:pyspark - join with OR conditionpyspark - 加入 OR 条件
【发布时间】:2021-03-18 08:52:45
【问题描述】:

如果至少满足两个条件之一,我想加入两个 pyspark 数据帧。

玩具数据:

df1 = spark.createDataFrame([
    (10, 1, 666),
    (20, 2, 777),
    (30, 1, 888),
    (40, 3, 999),
    (50, 1, 111),
    (60, 2, 222),
    (10, 4, 333),
    (50, None, 444),
    (10, 0, 555),
    (50, 0, 666)
    ],
    ['var1', 'var2', 'other_var'] 
)

df2 = spark.createDataFrame([
    (10, 1),
    (20, 2),
    (30, None),
    (30, 0)
    ],
    ['var1_', 'var2_'] 
)

我想保留df1 的所有行,其中var1 存在于df2.var1_ 的不同值中 OR var2 存在于df2.var2_ 的不同值中(但不是在该值为 0 的情况下)。

所以,预期的输出是

+----+----+---------+-----+-----+
|var1|var2|other_var|var1_|var2_|
+----+----+---------+-----+-----+
|  10|   1|      666|   10|    1|   # join on both var1 and var2
|  20|   2|      777|   20|    2|   # join on both var1 and var2
|  30|   1|      888|   10|    1|   # join on both var1 and var2
|  50|   1|      111|   10|    1|   # join on var2
|  60|   2|      222|   20|    2|   # join on var2
|  10|   4|      333|   10|    1|   # join on var1
|  10|   0|      555|   10|    1|   # join on var1
+----+----+---------+-----+-----+

在其他尝试中,我尝试过

cond = [(df1.var1 == (df2.select('var1_').distinct()).var1_) | (df1.var2 == (df2.filter(F.col('var2_') != 0).select('var2_').distinct()).var2_)]
df1\
    .join(df2, how='inner', on=cond)\
    .show()

+----+----+---------+-----+-----+
|var1|var2|other_var|var1_|var2_|
+----+----+---------+-----+-----+
|  10|   1|      666|   10|    1|
|  20|   2|      777|   20|    2|
|  30|   1|      888|   10|    1|
|  50|   1|      111|   10|    1|
|  30|   1|      888|   30| null|
|  30|   1|      888|   30|    0|
|  60|   2|      222|   20|    2|
|  10|   4|      333|   10|    1|
|  10|   0|      555|   10|    1|
|  10|   0|      555|   30|    0|
|  50|   0|      666|   30|    0|
+----+----+---------+-----+-----+

但我获得的行数比预期的多,var2 == 0 所在的行也被保留了。

我做错了什么?

注意:我没有使用 .isin 方法,因为我的实际 df2 大约有 20k 行,并且我读过 here 说这种具有大量 ID 的方法可能性能不佳.

【问题讨论】:

    标签: python dataframe apache-spark join pyspark


    【解决方案1】:

    试试下面的条件:

    cond = (df2.var2_ != 0) & ((df1.var1 == df2.var1_) | (df1.var2 == df2.var2_))
    df1\
        .join(df2, how='inner', on=cond)\
        .show()
    
    +----+----+---------+-----+-----+
    |var1|var2|other_var|var1_|var2_|
    +----+----+---------+-----+-----+
    |  10|   1|      666|   10|    1|
    |  30|   1|      888|   10|    1|
    |  20|   2|      777|   20|    2|
    |  50|   1|      111|   10|    1|
    |  60|   2|      222|   20|    2|
    |  10|   4|      333|   10|    1|
    |  10|   0|      555|   10|    1|
    +----+----+---------+-----+-----+
    

    条件应仅包括要连接的两个数据框中的列。如果要删除var2_ = 0,可以将它们作为连接条件,而不是作为过滤器。

    也不需要指定distinct,因为它不影响相等条件,而且还增加了一个不必要的步骤。

    【讨论】:

    • 非常感谢您的回答!不幸的是,我意识到我在所需的输出 (| 30| 1| 888| 30| null|) 中有一个重复的行,我不希望这样。另外,我不想加入 df2.var2_ 的空值(在我的情况下,它们可以被视为值 0)。代码应该如何更改?很抱歉给您带来不便。
    • 在这种情况下,代码更简单,您可以使用!= 0。请参阅编辑后的答案。
    猜你喜欢
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    相关资源
    最近更新 更多