Mincemeat:提供额外的参数来映射和减少闭包功能

时间:2014-06-13 23:27:12

标签: python-2.7 mapreduce closures mincemeat

我想尝试Mincemeat map / reduce Python应用程序进行矩阵乘法。我使用的是Python 2.7。我找到了几个网页,描述了如何在Java中使用Hadoop进行矩阵乘法,我一直在指这个http://importantfish.com/one-step-matrix-multiplication-with-hadoop/,因为它很简单,因为它显示的伪代码已经非常接近Python代码了。

我注意到在Java代码中也包含矩阵维度提供给map并通过Context类型的附加参数来减少函数。 Mincemeat没有提供这样的东西,但我得到了一个建议,我可以将这些值提供给我的地图并使用闭包减少函数。我写的map和reduce函数如下所示:

def make_map_fn(num_rows_result, num_cols_result):
    m = num_rows_result
    p = num_cols_result

    def map_fn(key, value):
        # value is ('A', i, j, a_ij) or ('B', j, k, b_jk)
        if value[0] == 'A':
            i = value[1]
            j = value[2]
            a_ij = value[3]

            for k in xrange(1, p):
                yield ((i, k), ('A', j, a_ij))
        else:
            j = value[1]
            k = value[2]
            b_jk = value[3]

            for i in xrange(1, m):
                yield ((i, k), ('B', j, b_jk))
    return map_fn


def make_reduce_fn(inner_dim):
    n = inner_dim

    def reduce_fn(key, values):
        # key is (i, k)
        # values is a list of ('A', j, a_ij) and ('B', j, b_jk)
        hash_A = {j: a_ij for (x, j, a_ij) in values if x == 'A'}
        hash_B = {j: b_jk for (x, j, b_jk) in values if x == 'B'}
        result = 0

        for j in xrange(1, n):
            result += hash_A[j] * hash_B[j]

        return (key, result)
    return reduce_fn

然后我将它们分配给Mincemeat:

s = mincemeat.Server()
s.mapfn = make_map_fn(num_rows_A, num_cols_B)
s.reducefn = make_reduce_fn(num_cols_A)

当我在Mincemeat中运行时,我收到此错误消息:

error: uncaptured python exception, closing channel <__main__.Client connected at 0x2ada4d0>
(<type 'exceptions.TypeError'>:arg 5 (closure) must be tuple
 [/usr/lib/python2.7/asyncore.py|read|83]
 [/usr/lib/python2.7/asyncore.py|handle_read_event|444]
 [/usr/lib/python2.7/asynchat.py|handle_read|140]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|found_terminator|96]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|process_command|194]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|set_mapfn|159])

我在网上搜索搜索条件,如| python closure必须是元组|我发现的东西似乎正在处理有人试图使用lambda或function()来构造函数的情况,并且需要确保在将它们定义为闭包时它们没有省略某些东西。在我的例子中,make_map_fn和make_reduce_fn返回的map_fn和reduce_fn值看起来像有效的函数对象,它们的func_closure值是包含我想要提供的数组维度的单元格的元组,但仍然缺少某些东西。我需要什么形式才能将这些功能传递给Mincemeat使用?

1 个答案:

答案 0 :(得分:0)

我不想成为坏消息的承载者,但这只是代码中一些一个一个错误的结果,加上你链接的网站提供的输入文件中的两个错误。它与您使用闭包无关,尽管存在误导性错误消息。

一个一个错误

请注意,伪代码中最内层的循环如下所示:

for k = 1 to p:
for i = 1 to m:
for j = 1 to n:

在伪代码中,这通常表示包含端点,即for k = 1 to p表示k = 1, 2, ..., p-1, p。另一方面,代码中的相应循环如下所示:

for k in xrange(1, p):
for i in xrange(1, m):
for j in xrange(1, n):

当然,xrange(1, p)会产生1,2,......,p-2,p-1。假设您将矩阵从0索引(就像它们在您链接的站点上所做的那样),所有xranges应该从0开始(例如xrange(0, p)),因为它们在Java代码中的等价物(for (int k = 0; k < p; k++))。这解决了您的一个问题。

输入文件错误

如果你没有抓住这个,那么网站提供的A和B的输入文件是不正确的 - 他们忘记了两个矩阵的(0,0)条目。特别是,您应该在表单A,0,0,0.0的开头添加一行,并在B,0,0,0.0表单的9到10之间添加一行。 (我猜你究竟放在哪里并不重要,但为了保持一致性,你可以将它们放在自然适合的地方。)


一旦我纠正了这两个错误,mincemeat就会给出我们期望的结果(格式化):

{(0, 1): ((0, 1), 100.0), 
 (1, 2): ((1, 2), 310.0), 
 (0, 0): ((0, 0),  90.0), 
 (0, 2): ((0, 2), 110.0), 
 (1, 0): ((1, 0), 240.0), 
 (1, 1): ((1, 1), 275.0)}

我还没弄清楚错误消息到底发生了什么,但我认为这归结为map函数中不正确的循环索引导致垃圾数据传递给reduce节点,这是为什么错误提到reduce函数。

基本上,会发生的情况是,reduce函数中的hash_Ahash_B有时没有相同的键,所以当你尝试乘以hash_A[j] * hash_B[j]时,你会得到一个KeyError因为j不是其中之一的密钥,而是在上游的某个地方被捕获,而是以TypeError重新命名。