spark

时间:2016-07-05 20:26:56

标签: apache-spark pyspark

我想在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时,它是空的。怎么了?

2 个答案:

答案 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']