基于PySpark中另一个数据帧的列值更新列中的值

基于PySpark中另一个数据帧的列值更新列中的值,pyspark,intersection,collect,Pyspark,Intersection,Collect,我在PySpark中有两个数据帧:df1 和df2: 我想在df1中创建一个新列,用于更新中的值 items1列,因此它只保留也出现在df2中items2的任何行中的值。结果应如下所示: +---+-----------------+----------------------+ |id1| items1| items1_updated| +---+-----------------+----------------------+ | 0| [B, C

我在PySpark中有两个数据帧:df1

和df2:

我想在df1中创建一个新列,用于更新中的值 items1列,因此它只保留也出现在df2中items2的任何行中的值。结果应如下所示:

+---+-----------------+----------------------+
|id1|           items1|        items1_updated|
+---+-----------------+----------------------+
|  0|     [B, C, D, E]|             [B, C, E]|
|  1|        [E, A, C]|             [E, A, C]|
|  2|     [F, A, E, B]|             [A, E, B]|
|  3|        [E, G, A]|                [E, A]|
|  4|  [A, C, E, B, D]|          [A, C, E, B]|
+---+-----------------+----------------------+

我通常会使用collect来获取items2列中所有值的列表,然后使用应用于items1中每一行的udf来获取交集。但是数据非常大,超过1000万行,我无法使用collect获得这样的列表。在以数据帧格式保存数据时,有没有办法做到这一点?或者不使用collect的其他方法?

您要做的第一件事是df2.items2中的值,以便数组的内容位于单独的行上:

从pyspark.sql.functions导入explode df2=df2.selectexplodeitems2.aliasitems2 df2.show +---+ |项目2| +---+ |B| |A| |C| |E| +---+ 这假设df2.items2中的值是不同的-如果不是,则需要添加df2=df2.distinct

选项1:使用交叉连接:

现在,您可以将新的df2交叉连接回df1,并仅保留df1.items1包含df2.items2中元素的行。我们可以通过使用实现这一点,这使我们能够

过滤后,按id1和items1分组,并使用

从pyspark.sql.functions导入expr,收集\u列表 df1.aliasl.crossJoindf2.aliasr\ .其中exprarray_包含SL.项目1,r.项目2\ .groupByl.id1,l.items1\ .aggcollect_listr.items2.aliasitems1_已更新\ 显示 +--+--------+-------+ |id1 |项目1 |项目1 |更新| +--+--------+-------+ |1 |[E,A,C]|[A,C,E]| |0 |[B,C,D,E]|[B,C,E]| |4 |[A,C,E,B,D]|[B,A,C,E]| |3 |[E,G,A]|[A,E]| |2 |[F,A,E,B]|[B,A,E]| +--+--------+-------+ 选项2:分解df1.items1并左连接:

另一个选项是分解df1中items1的内容并进行左连接。在加入之后,我们必须像上面那样进行类似的分组和聚合。这是因为collect_list将忽略非匹配行引入的空值

df1.withColumnitems1,explodeitems1.aliasl\ .joindf2.aliasr,on=exprl.items1=r.items2,how=left\ .groupByl.id1\ 阿格先生 收集列表l.items1.aliasitems1, collect_listr.items2.aliasitems1_已更新 显示 +--+--------+-------+ |id1 |项目1 |项目1 |更新| +--+--------+-------+ |0 |[E,B,D,C]|[E,B,C]| |1 |[E,C,A]|[E,C,A]| |3 |[E,A,G]|[E,A]| |2 |[F,E,B,A]|[E,B,A]| |4 |[E,B,D,C,A]|[E,B,C,A]| +--+--------+-------+
items1和items2列的数据类型是arraytype还是string?非常感谢您的帮助。多么优雅的解决方案!它在本地运行良好,明天我将在更大的数据上进行测试。但是你的解释非常清楚,帮助我理解为什么应该使用这种方法。你介意帮我看一个相关的问题吗?
+---+-----------------+
|id2|           items2|
+---+-----------------+
|001|              [B]|
|002|              [A]|
|003|              [C]|
|004|              [E]|
+---+-----------------+ 
+---+-----------------+----------------------+
|id1|           items1|        items1_updated|
+---+-----------------+----------------------+
|  0|     [B, C, D, E]|             [B, C, E]|
|  1|        [E, A, C]|             [E, A, C]|
|  2|     [F, A, E, B]|             [A, E, B]|
|  3|        [E, G, A]|                [E, A]|
|  4|  [A, C, E, B, D]|          [A, C, E, B]|
+---+-----------------+----------------------+