Python - 在MapReduce中实现连接 - 减速器输出的问题

时间:2013-06-03 23:19:02

标签: python mapreduce jointable reducers

这是我在Coursera上进行数据科学课程中的硬件任务的求助,因为我无法在Coursera论坛上得到任何建议。我已经制作了我的代码,但不幸的是输出没有返回预期的结果。这是手头的问题:

任务:将关系联接实现为MapReduce查询

输入(Mapper):

输入将是格式化为字符串列表的数据库记录。 每个列表元素对应于其对应记录中的不同字段。 每个记录中的第一个项目(索引0)是一个字符串,用于标识记录源自哪个表。该字段有两个可能的值:

  1. 'line_item'表示记录是订单项。 2.“order”表示记录是订单。
  2. 每条记录中的第二个元素(索引1)是order_id。 LineItem记录有17个元素,包括标识符字符串。 订单记录包含10个元素,包括标识符字符串。

    输出(减速器):

    输出应该是连接记录。

    结果应该是长度为27的单个列表,其中包含订单记录中的字段,后跟行项目记录中的字段。每个列表元素都应该是一个字符串。

    我的代码是:

    import MapReduce
    import sys
    
    """
    Word Count Example in the Simple Python MapReduce Framework
    """
    
    mr = MapReduce.MapReduce()
    
    # =============================
    # Do not modify above this line
    
    record = open(sys.argv[1]) # this read input, given by instructor
    
    def mapper(record):
    key = record[1] # assign order_id from each record as key
    value = list(record) # assign whole record as value for each key
    mr.emit_intermediate(key, value) # emit key-value pairs
    
    def reducer(key, value):
        new_dict = {} # create dict to keep track of records
        if not key in new_dict:
            new_dict[key] = value
        else:
            new_dict[key].extend(value)
        for key in new_dict:
            if len(new_dict[key]) == 27:
                mr.emit(new_dict[key])
    
    # Do not modify below this line
    # =============================
    if __name__ == '__main__':
      inputdata = open(sys.argv[1])
      mr.execute(inputdata, mapper, reducer)
    

    我收到的错误消息是“预期:31条记录,得到0”。

    此外,预期的输出记录应该是这样的 - 只有一个列表,所有记录集中在一起,没有重复数据删除。

    ["order", "5", "44485", "F", "144659.20", "1994-07-30", "5-LOW", "Clerk#000000925", "0", "quickly. bold deposits sleep slyly. packages use slyly", "line_item", "5", "37531", "35", "3", "50", "73426.50", "0.08", "0.03", "A", "F", "1994-08-08", "1994-10-13", "1994-08-26", "DELIVER IN PERSON", "AIR", "eodolites. fluffily unusual"]
    

    对于长时间的问题很抱歉,这有点乱,但我希望答案对某人来说是显而易见的。

    类似的代码对我有用:

    def mapper(record):
        # key: document identifier
        # value: document contents
        friend = record[0]
        value = 1
        mydict = {}
        mr.emit_intermediate(friend, value)
        mydict[friend] = int(value)
    
    
    def reducer(friend, value):
        # key: word
        # value: list of occurrence counts
        newdict = {}
        if not friend in newdict:
            newdict[friend] = value
        else:
        newdict[friend] = newdict[friend] + 1
        for friend in newdict:
        mr.emit((friend, (newdict[friend])))
    

    谢谢! 塞吉

4 个答案:

答案 0 :(得分:3)

实际上你不必使用new_dict。由于您必须打印“加入”,并且您知道订单始终位于值列表中的索引0中,而列表的其余部分是 line_item 此代码应该这样做:

import MapReduce
import sys

"""
Word Count Example in the Simple Python MapReduce Framework
"""

mr = MapReduce.MapReduce()

# =============================
# Do not modify above this line

def mapper(record):
    key = record[1] # assign order_id from each record as key
    value = list(record) # assign whole record as value for each key
    mr.emit_intermediate(key, value) # emit key-value pairs

def reducer(key, value):
    for index in range (1, len(value)):
        mr.emit(value[0] + value[index])

# Do not modify below this line
# =============================
if __name__ == '__main__':
  inputdata = open(sys.argv[1])
  mr.execute(inputdata, mapper, reducer)

答案 1 :(得分:0)

我发现这段代码有些不对劲。首先是这一行:

record = open(sys.argv[1])

我觉得奇怪的是,这个record变量从未在代码中的任何其他位置使用过。即使mapper函数定义如下:

def mapper(record):
    ...

... recordmapper函数的本地。它与第一个record的范围不同。无论传递给mapper的数据是什么,都会分配给其本地record并相应地使用,并且永远不会触及分配给第一个record的文件对象。不过,我并不认为这与错误有关。因为第一个record未在其他地方使用,所以您可以非常安全地删除该行。

然后是reducer函数:

def reducer(key, value): # reducer should take 2 inputs according to the task
    if key in new_dict: # checking if key already added to dict
        new_dict[key].extend(list(value)) # if yes just append all records to the value
    new_dict[key] = list(value) # if not create new key and assign record to value
    for key in new_dict:
        if len(new_dict[key]) == 27: # checks to emit only records found in both tables
            mr.emit(new_dict[key])

您自己的评论提供了问题的线索。首先,你说你正在检查密钥是否已经在dict中。如果是这样,只需将所有记录附加到值。如果没有,请创建一个新密钥并将记录分配给该值。

问题在于与“if not”评论相关联的行。如果第一个if测试失败,那么它应该是真正应该做的,那么它应该以{{1​​}}行开头:

else

您编写它的方式,即使 ... if key in new_dict: # checking if key already added to dict new_dict[key].extend(list(value)) # if yes just append all records to the value else: new_dict[key] = list(value) # if not create new key and assign record to value ... 测试成功并将数据附加到键的现有值,它也会立即踩踏该更改。换句话说,该键的值不会增长。它总是代表最近提交的密钥值。

以下是使用所有建议更改编辑的完整代码:

if

答案 2 :(得分:0)

不知道它是否仍然相关,只是想指出,正如Justin建议的那样,每次调用reducer时都会重置new_dict。一种方法是发出2个键值对。 说你有2行 -

  1. order_id,line_item_id,Order_name

    1    ,      2      ,   'abc'
    
  2. line_item_id,line_item_location

    2        ,     'xyz'
    
  3. 我们希望输出为 -

     1,2,'abc','xyz'
    

    从mapper中发出2个键值对,并将join列作为公共键 -

    (2,[1,'abc']) and (2,['xyz'])
    
    因此,在reducer中,输入将是 -

    (2,[[1,'abc'],['xyz']])
    

    从那里尝试并操纵数据以获得所需的输出。

    (供参考 - 我在我的M / R工作中使用python dumbo框架)

答案 3 :(得分:0)

:back