如何在任务图中更改全局变量值或使用Python在Apache Spark中减少

时间:2015-06-23 01:51:26

标签: python python-2.7 apache-spark

我有以下代码:

import sys
from pyspark import SparkContext

def mapper(array):
    aux = []
    array = str(array)
    aux = array.split(' | ')
    return {(aux[0][:-1],aux[1][:-1]): [(aux[0][1:],aux[1][1:])]}

def reducer(d1, d2):
    for k in d1.keys():
        if d2.has_key(k):
            d1[k] = d1[k] + d2[k]
            d2.pop(k)
    d1.update(d2)
    return d1 

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: bruijn <file>")
        exit(-1)
    sc = SparkContext(appName="Assembler")
    kd = sys.argv[1].lstrip('k').rstrip('mer.txt').split('d')
    k, d = int(kd[0]), int(kd[1])
    dic = sc.textFile(sys.argv[1],False).map(mapper).reduce(reducer)
    filepath = open('DeBruijn.txt', 'w')
    for key in sorted(dic):
        filepath.write(str(key) + ' -> ' + str(dic[key]) + '\n')
    filepath.close()        
    print('De Bruijn graph successfully generated!')
    sc.stop()

我想在main中创建一个名为vertexes的空列表,并使映射器在其中附加元素。但是,使用关键字global不起作用。我尝试过使用累加器,但累加器的值不能在任务中获取。

3 个答案:

答案 0 :(得分:2)

我通过创建一个与列表一起使用的自定义类型的Accumulatior来弄清楚如何做到这一点。在我的代码中,我所要做的就是插入以下导入并实现以下类:

from pyspark.accumulators import AccumulatorParam

class VectorAccumulatorParam(AccumulatorParam):
    def zero(self, value):
        return []
    def addInPlace(self, val1, val2):
        return val1 + [val2] if type(val2) != list else val2 #Had to do this check because without it the result would be a list with all the tuples inside of another list.

我的映射器功能如下:

def mapper(array):
    global vertexes
    aux = []
    array = str(array)
    aux = array.split(' | ')
    vertexes += (aux[0][:-1], aux[1][:-1]) #Adding a tuple into accumulator
    vertexes += (aux[0][1:], aux[1][1:]) #Adding a tuple into accumulator
    return {(aux[0][:-1],aux[1][:-1]): [(aux[0][1:],aux[1][1:])]

在调用mapper函数之前,在main函数内部我创建了累加器:

vertexes = sc.accumulator([],VectorAccumulatorParam())

mapper / reducer函数调用后,我可以得到结果:

vertexes = list(set(vertexes.value))

答案 1 :(得分:1)

Herio Sousa的VectorAccumulatorParam是一个好主意。但是,您实际上可以使用内置类AddingAccumulatorParam,它与VectorAccumulatorParam基本相同。

在此处查看原始代码https://github.com/apache/spark/blob/41afa16500e682475eaa80e31c0434b7ab66abcb/python/pyspark/accumulators.py#L197-L213

答案 2 :(得分:0)

正如您所注意到的,您无法将元素附加到映射器内(或者您可以将元素附加到映射器内部,但更改不会推广到任何其他映射器或您的主函数)。正如您已经注意到累加器允许您附加元素,但是它们只能在驱动程序中读取并写入执行程序中。如果你想要不同的密钥,你可以让另一个映射器输出密钥并在其上调用distinct。您可能还想查看reduceByKey而不是您正在使用的reduce。