Python-在MapReduce中实现连接-reducer输出的问题

Python-在MapReduce中实现连接-reducer输出的问题,python,mapreduce,jointable,reducers,Python,Mapreduce,Jointable,Reducers,这是我在Coursera上学习的数据科学课程中关于硬件任务的求助,因为我在Coursera论坛上找不到任何建议。我已经编写了代码,但不幸的是,输出没有返回预期的结果。下面是当前的问题: 任务:将关系联接实现为MapReduce查询 输入(映射器): 输入将是格式化为字符串列表的数据库记录。 每个列表元素对应于其相应记录中的不同字段。 每个记录中的第一项(索引0)是一个字符串,用于标识记录来自哪个表。此字段有两个可能的值: “行项目”表示记录是行项目。 2.“订单”表示记录是订单 每个记录中的第二

这是我在Coursera上学习的数据科学课程中关于硬件任务的求助,因为我在Coursera论坛上找不到任何建议。我已经编写了代码,但不幸的是,输出没有返回预期的结果。下面是当前的问题:

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

输入(映射器):

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

  • “行项目”表示记录是行项目。 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])))
    
    谢谢!
    Sergey

    我发现这个代码有几处不对劲。首先是这一行:

    record = open(sys.argv[1])
    
    我觉得奇怪的是,这个
    记录
    变量从未在代码中的任何其他地方使用过。即使映射器功能定义如下:

    def mapper(record):
        ...
    
    …该
    记录
    映射器
    功能的本地记录。它的作用域与第一条
    记录的作用域不同。传递给
    映射器的任何数据都将分配给其本地
    记录
    ,并相应地使用,并且分配给第一条
    记录
    的文件对象永远不会被触及。不过,我觉得这与错误无关。因为第一条
    记录
    没有在其他任何地方使用,所以您可以非常安全地删除该行

    然后是
    减速器
    功能:

    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”注释关联的行。如果第一次
    测试失败时确实应该这样做,那么应该在测试前加一行
    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
        ...
    
    按照您编写它的方式,即使
    测试成功,并且它将数据附加到键的现有值,它也会立即跳过该更改。换句话说,该键的值不会增长。它总是表示最近提交的密钥值

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

    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
    
    new_dict = {} # create dict to keep track of records
    
    def reducer(key, value):
        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)
    

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

    record = open(sys.argv[1])
    
    我觉得奇怪的是,这个
    记录
    变量从未在代码中的任何其他地方使用过。即使映射器
    功能定义如下:

    def mapper(record):
        ...
    
    …该
    记录
    映射器
    功能的本地记录。它的作用域与第一条
    记录的作用域不同。传递给
    映射器的任何数据都将分配给其本地
    记录
    ,并相应地使用,并且分配给第一条
    记录
    的文件对象永远不会被触及。不过,我觉得这与错误无关。因为第一条
    记录
    没有在其他任何地方使用,所以您可以非常安全地删除该行

    然后是
    减速器
    功能:

    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”注释关联的行。如果第一次
    测试失败时确实应该这样做,那么应该在测试前加一行
    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
        ...
    
    按照您编写它的方式,即使
    测试成功,并且它将数据附加到键的现有值,它也会立即跳过该更改。换句话说,该键的值不会增长。它总是表示最近提交的密钥值

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

    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
    
    new_dict = {} # create dict to keep track of records
    
    def reducer(key, value):
        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)
    

    实际上,您不必使用new dict。因为您必须打印“join”,并且您知道订单始终位于值列表的索引0中,而列表的其余部分是行项目,因此此代码应能做到:

    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)
    

    实际上,您不必使用new dict。因为您必须打印“join”,并且您知道订单始终位于值列表的索引0中,而列表的其余部分是行项目,因此此代码应能做到:

    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)
    

    不知道它是否仍然相关,只是想指出,正如Justin所建议的,每次调用减速器时,新的dict都会重置。一种方法是发出两个键和值对。 假设你有两排-

  • 订单id、行项目id、订单名称

    1    ,      2      ,   'abc'
    
  • 行项目标识,行项目位置

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

     1,2,'abc','xyz'
    
    从映射器发出2个键、值对,并将联接列作为公共键-

    (2,[1,'abc']) and (2,['xyz'])
    
    因此,在减速机中,输入为-

    (2,[[1,'abc'],['xyz']])
    
    从那以后试试看