Pyspark映射调用的函数不会修改全局列表

时间:2019-11-19 21:13:17

标签: python apache-spark lambda pyspark global-variables

我已经定义了在全局列表 signature 上运行的此函数,我已经测试了该函数并且可以正常工作。

def add_to_list_initial(x):
    global signature
    signature.append([x])
    print(x)
    return x

打印将检查是否调用了该函数。

我必须为Pyspark rdd的每一行运行此功能,所以我编写了这段代码:

rdd.map(lambda x: min([str(int.from_bytes(hash_functions[0](str(shingle)), 'big')) for shingle in x])).map(lambda x: add_to_list_initial(x))

但是没有调用该函数,为避免map的“懒惰”,我尝试通过这种方式在最后添加“ .count()”:

rdd.map(lambda x: min([str(int.from_bytes(hash_functions[0](str(shingle)), 'big')) for shingle in x])).map(lambda x: add_to_list_initial(x)).count()

现在完成打印。我什至检查了列表 signature 是否已更新,但是,当我尝试打印列表的大小时,结果将为0,因为列表根本没有更新。

我什至尝试使用 foreach 代替 map ,但是结果是相同的:

rdd1 = rdd.map(lambda x: min([str(int.from_bytes(hash_functions[0](str(shingle)), 'big')) for shingle in x]))
rdd1.foreach(add_to_list_initial)

这些是输出的第一行,它们在我的Pycharm控制台上甚至打印时都以红色显示:

19/11/19 21:56:51 WARN TaskSetManager: Stage 2 contains a task of very large size (76414 KB). The maximum recommended task size is 100 KB.
1000052032941703168135263382785614272239884872602
1001548144792848500380180424836160638323674923493
1001192257270049214326810337735024900266705408878
1005273115771118475643621392239203192516851021236
100392090499199786517408984837575190060861208673
1001304115299775295352319010425102201971454728176
1009952688729976061710890304226612996334789156125
1001064097828097404652846404629529563217707288121
1001774517560471388799843553771453069473894089066
1001111820875570611167329779043376285257015448116
1001339474866718130058118603277141156508303423308
1003194269601172112216983411469283303300285500716
1003194269601172112216983411469283303300285500716
1003194269601172112216983411469283303300285500716
1003194269601172112216983411469283303300285500716
1003194269601172112216983411469283303300285500716

如何有效解决问题? 我使用Python 3.7和Pyspark 3.2.1

我这样做是为了为文档ID为

的每组散列带状疱获得最小散列签名。

然后,为了计算其他排列,我想以此方式进行操作:

def add_to_list(x):
    global num_announcements
    global signature
    global i
    print(len(signature))
    if i == num_announcements:
        i = 0
    signature[i].append(x)
    print(i)
    i += 1


for function in hash_functions[1:]:
    rdd.map(lambda x: min([str(int.from_bytes(function(str(shingle)), 'big')) for shingle in x])).foreach(add_to_list)

但是问题是相同的。 我什至会为我的哈希算法问题提出建议,但问题是关于上述问题。

2 个答案:

答案 0 :(得分:0)

我以这种方式解决了,即使我总体上没有找到有用的解决方案。

signatures = shingles.flatMap(lambda x: [[(x[1]+1, (x[1]+1)%lsh_b), min([int.from_bytes(function(str(s)), 'big') for s in x[0]])] for function in hash_functions]).cache()

答案 1 :(得分:-1)

可以使用类(Callable)代替全局变量。

例如:

from collections.abc import Callable


class Signature(Callable):
    def __init__(self):
        self.signature = []

    def __call__(self, x):
        self.signature.append([x])
        return x

然后,您可以在需要的地方实例化此可调用项:

add_to_list_initial = Signature()

rdd.map(lambda x: min([str(int.from_bytes(hash_functions[0](str(shingle)), 'big')) for shingle in x])).map(
    lambda x: add_to_list_initial(x)
).count()

print(add_to_list_initial.signature)

注意:您可以在这里避免使用lambda表达式,简化为:

rdd.map(lambda x: min([str(int.from_bytes(hash_functions[0](str(shingle)), 'big')) for shingle in x])).map(
    add_to_list_initial
).count()

编辑

要允许腌制,可以使用:

class Signature:
    def __init__(self):
        self.signature = []

    def __call__(self, x):
        self.signature.append([x])
        return x