我在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))
对于较小的数据集,它运行良好,但对于较大的数据集,收集会导致异常。我想知道是否有更好的逻辑来计算此步骤。
答案 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(...)在大多数情况下也转换为联接,除非(...)是一小组数据。
答案 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)
所以这里有两个问题:
这可以通过在两列而不是一列上执行内部联接来完成。这是该代码:
# 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)
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。尝试增加更多的工人并增加内存。