如何根据另一个数据框过滤一个数据框?

时间:2019-07-14 15:15:16

标签: apache-spark dataframe pyspark pyspark-sql

我在pyspark中有两个数据框:

d1: (x,y,value)和d2:(k,v, value)。 d1中的条目是唯一的(您可以认为x列是唯一的,y列是唯一的)

x y value
a b 0.2
c d 0.4
e f 0,8

d2是以下格式:

k v value
a c 0.7
k k 0.3
j h 0.8
e p 0.1
a b 0.1

我需要过滤d2并在d1上同时出现。也就是说,a , c 0.7 and e p 0.1应该被删除,因为a只能与b一起出现,并且类似地对于e也可以出现。

我试图从d1中选择x和y列。

sourceList = df1.select("x").collect()
sourceList = [row.x for row in sourceList]

sourceList_b = sc.broadcast(sourceList)

然后

check_id_isin = sf.udf(lambda x: x in sourceList , BooleanType())
d2 = d2.where(~d2.k.isin(sourceList_b.value))

对于较小的数据集,它运行良好,但对于较大的数据集,收集会导致异常。我想知道是否有更好的逻辑来计算此步骤。

3 个答案:

答案 0 :(得分:1)

您可能想做的是从关系角度考虑这一点。在d1.x = d2.k和d1.y = d2.kv上将d1和d2连接起来。内部联接将从D2中删除所有在d1中没有对应对的记录。与广播交换相比,通过join join spark将对数据进行集群范围的混洗,从而实现更大的并行性和可扩展性,广播交换通常将数据的上限限制为约10mb(这是spark用作洗净之间的切入点)加入和广播加入。

在FYI WHERE中,(a,b)IS IN(...)在大多数情况下也转换为联接,除非(...)是一小组数据。

https://github.com/vaquarkhan/vaquarkhan/wiki/Apache-Spark--Shuffle-hash-join-vs--Broadcast-hash-join

答案 1 :(得分:1)

一种方法是将join从d1转换为d2,然后使用合并填充v列中y列中的y值,然后过滤y和v不同的行,例如:

import pyspark.sql.functions as F

(d2.join( d1.select('x','y').withColumnRenamed('x','k'), #rename x to k for easier join
          on=['k'], how='left') #join left to keep only d2 rows
   .withColumn('y', F.coalesce('y', 'v')) #fill the value missing in y with the one from v
   .filter((F.col('v') == F.col('y'))) #keep only where the value in v are equal to y
   .drop('y').show()) #drop the column y not necessary

您会得到:

+---+---+-----+
|  k|  v|value|
+---+---+-----+
|  k|  k|  0.3|
|  j|  h|  0.8|
+---+---+-----+

,并且还应保留夫妇(x,y)中两个值都在(k,v)中的任何行

答案 2 :(得分:1)

所以这里有两个问题:

  1. 连接这两个表的逻辑:

这可以通过在两列而不是一列上执行内部联接来完成。这是该代码:

# Create an expression wherein you do an inner join on two cols
joinExpr = ((d1.x = d2.k) & (d1.y == d2.y))
joinDF = d1.join(d2, joinExpr)
  1. 第二个问题是速度。有多种修复方法。这是我的前两个:

a。如果其中一个数据帧比另一个数据帧小得多(通常小于2 GB),则可以使用广播联接。它本质上会将较小的数据帧复制到所有工作程序,因此在加入时无需进行洗牌。这是一个示例:

from pyspark.sql.functions import broadcast

joinExpr = ((d1.x = d2.k) & (d1.y == d2.y))
joinDF = d1.join(broadcast(d2), joinExpr)

b。尝试增加更多的工人并增加内存。