我有以下代码:
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不起作用。我尝试过使用累加器,但累加器的值不能在任务中获取。
答案 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基本相同。
答案 2 :(得分:0)
正如您所注意到的,您无法将元素附加到映射器内(或者您可以将元素附加到映射器内部,但更改不会推广到任何其他映射器或您的主函数)。正如您已经注意到累加器允许您附加元素,但是它们只能在驱动程序中读取并写入执行程序中。如果你想要不同的密钥,你可以让另一个映射器输出密钥并在其上调用distinct。您可能还想查看reduceByKey而不是您正在使用的reduce。