我想在pyspark中定义一个类型为List
的累加器,并为工作节点累积字符串值。这是我的代码:
class ListParam(AccumulatorParam):
def zero(self, v):
return []
def addInPlace(self, acc1, acc2):
acc1.extend(acc2)
return acc1
然后我定义了这种类型的累加器,如下所示
accu = sc.accumulator([], ListParam())
然后在执行程序中为它添加不同的值,如下所示
accu.add("abc")
我希望值abc
在累加器中只显示一个值,但累加器会添加三个不同的值(一个pr字符),当我查看驱动程序中的accu
值时它看起来像['a','b','c']
。如何更改它以使它不会将每个字符作为累加器中的单独条目添加?
-------------- ----------------编辑
我为累加器定义了另一个自定义类,如下所示
class VectorAccumulatorParam(AccumulatorParam):
def zero(self, value):
return [0.0] * len(value)
def addInPlace(self, val1, val2):
for i in range(len(val1)):
val1[i] += val2[i]
return val1
在工人中我有以下代码
global accu
accu += [accuracy]
但是当我在驱动程序中打印accu
时,它是空的。怎么了?
答案 0 :(得分:0)
您是否尝试明确告诉spark执行处理累加器的操作?您应该知道spark's operations are lazy,并且很多时候需要调用rdd.collect()来实际执行映射
答案 1 :(得分:0)
我遇到了和你一样的问题,看到了这个问题并使用了你的代码。以下代码在带有(Py)Spark 2的HDP 2.5集群上运行,并为我工作。
我上了你的课并改了它以附加一个字符串。
from pyspark.accumulators import AccumulatorParam
class ListParam(AccumulatorParam):
def zero(self, v):
return []
def addInPlace(self, variable, value):
variable.append(value)
return variable
然后我创建了一个累加器变量和一个测试数据帧:
accu = sc.accumulator([], ListParam())
rdd = sc.parallelize([(0,1), (0,1), (0,2), (1,2), (1,10), (1,20), (3,18), (3,18), (3,18)])
df=rdd.toDF(['id','score'])
对于我正在处理的程序,我必须将我的数据帧重新分区为单个大小。所以我也试过这个:
df.repartition(2)
之后我创建了一个worker函数,它将一个字符串附加到累加器列表:
def worker(row):
global accu
accu.add("Moin")
现在我可以调用datafame的foreach循环(每个分区都是一个任务):
df.foreach(worker)
每个任务都会使用自己的字符串列表将项目附加到列表中:
>>> accu
Accumulator<id=66, value=[['Moin', 'Moin', 'Moin', 'Moin'], ['Moin', 'Moin', 'Moin', 'Moin', 'Moin']]>
所以我必须将每个子列表添加到结果列表
中res = []
for i in range(0, len(accu.value)):
res += accu.value[i]
结果:
>>> res
['Moin', 'Moin', 'Moin', 'Moin', 'Moin', 'Moin', 'Moin', 'Moin', 'Moin']