pyspark:在同一列(使用数组)上使用多个UDF函数时出现意外行为

pyspark:在同一列(使用数组)上使用多个UDF函数时出现意外行为,pyspark,user-defined-functions,Pyspark,User Defined Functions,有人知道当您使用多个udf函数时会发生什么吗: from pyspark.sql.functions import udf mylist = [ [[1,2,3]], [[4,5,6]] ] def f1(tlist): tlist[0]=111 return 'result f1 is: {}'.format(tlist) f1_udf = udf(f1, ) def f2(tlist): tlist[1]=222 return 'resu

有人知道当您使用多个udf函数时会发生什么吗:

from pyspark.sql.functions import udf

mylist = [
    [[1,2,3]],
    [[4,5,6]]
]

def f1(tlist):
    tlist[0]=111
    return 'result f1 is: {}'.format(tlist)
f1_udf = udf(f1, )

def f2(tlist):
    tlist[1]=222
    return 'result f2 is: {}'.format(tlist)
f2_udf = udf(f2, )

df = spark().createDataFrame(mylist).toDF('arr')
df.show()
我创建了一个测试数据帧和两个示例udf函数:

from pyspark.sql.functions import udf

mylist = [
    [[1,2,3]],
    [[4,5,6]]
]

def f1(tlist):
    tlist[0]=111
    return 'result f1 is: {}'.format(tlist)
f1_udf = udf(f1, )

def f2(tlist):
    tlist[1]=222
    return 'result f2 is: {}'.format(tlist)
f2_udf = udf(f2, )

df = spark().createDataFrame(mylist).toDF('arr')
df.show()
给出以下结果:

+---------+
|      arr|
+---------+
|[1, 2, 3]|
|[4, 5, 6]|
+---------+
然后,我分别应用每个函数:

df.withColumn('f1', f1_udf('arr')).show(10, False)
给予

给予

但是,这里开始出现意外行为

(df
 .withColumn('f1', f1_udf('arr'))
 .withColumn('f2', f2_udf('arr'))
).show(10, False)
给出意外的结果,在第二次函数调用中混合两个函数的结果

+---------+-------------------------+---------------------------+
|arr      |f1                       |f2                         |
+---------+-------------------------+---------------------------+
|[1, 2, 3]|result f1 is: [111, 2, 3]|result f2 is: [111, 222, 3]|
|[4, 5, 6]|result f1 is: [111, 5, 6]|result f2 is: [111, 222, 6]|
+---------+-------------------------+---------------------------+
                                                    ^^^ : unexpected result
更改调用函数的顺序时,

(df
 .withColumn('f2', f2_udf('arr'))
 .withColumn('f1', f1_udf('arr'))
).show(10, False)
给出了一个不同的、也是意外的结果:

+---------+-------------------------+---------------------------+
|arr      |f2                       |f1                         |
+---------+-------------------------+---------------------------+
|[1, 2, 3]|result f2 is: [1, 222, 3]|result f1 is: [111, 222, 3]|
|[4, 5, 6]|result f2 is: [4, 222, 6]|result f1 is: [111, 222, 6]|
+---------+-------------------------+---------------------------+
                                                         ^^^ : different unexpected result
在固定的、未更改的spark列上调用函数似乎不是相互独立的,这意味着如果我们同时调用这两个函数(即使中间有很多其他代码),则会在下一个函数中混合第一个函数调用的结果。。。
或者,我遗漏了什么吗?

Spark将相同的数组传递到两个函数
f1
f2
。当第一个函数更改数组的内容时,第二个函数也会看到这些更改。您可以看到,如果您添加该行

print(“f1:id的数组是{},内容是{}”。格式(id(tlist),tlist))
到第一个函数和

print(“f2:数组的id为{},内容为{}”。格式(id(tlist),tlist))
到第二个函数

这张照片

f1:数组id为139782923179912,内容为[1,2,3]
f2:数组的id为139782923179912,内容为[111,2,3]
f1:数组id为139782923180040,内容为[4,5,6]
f2:数组id为139782923180040,内容为[111,5,6]
(可能打印有点乱)

因此,第二个函数可以看到在第一个函数中更改的数组

要解决此问题,函数应创建自己的阵列副本,并仅更改这些副本:

def f1(t列表):
打印(“f1:数组的id为{},内容为{}”。格式(id(tlist),tlist))
newlist=tlist.copy()
新列表[0]=111
返回“结果f1为:{}”。格式(newlist)
对于
f2

获得预期行为的另一种方法是将两个UDF声明为:

f1\u udf=F.udf(f1,).asNondeterministic()
f2_udf=F.udf(f2,).asNondeterministic()
然而,我无法解释为什么这有帮助

(df
 .withColumn('f2', f2_udf('arr'))
 .withColumn('f1', f1_udf('arr'))
).show(10, False)
+---------+-------------------------+---------------------------+
|arr      |f2                       |f1                         |
+---------+-------------------------+---------------------------+
|[1, 2, 3]|result f2 is: [1, 222, 3]|result f1 is: [111, 222, 3]|
|[4, 5, 6]|result f2 is: [4, 222, 6]|result f1 is: [111, 222, 6]|
+---------+-------------------------+---------------------------+
                                                         ^^^ : different unexpected result