使用MRJob的多个输入

时间:2012-02-15 22:37:22

标签: python mapreduce mrjob

我正在尝试将Yelp的Python API用于MapReduce,MRJob。他们简单的单词计数器示例是有道理的,但我很好奇如何处理涉及多个输入的应用程序。例如,不是简单地计算文档中的单词,而是将向量乘以矩阵。我提出了这个功能的解决方案,但感觉很傻:

class MatrixVectMultiplyTast(MRJob):
    def multiply(self,key,line):
            line = map(float,line.split(" "))
            v,col = line[-1],line[:-1]

            for i in xrange(len(col)):
                    yield i,col[i]*v

    def sum(self,i,occurrences):
            yield i,sum(occurrences)

    def steps(self):
            return [self.mr (self.multiply,self.sum),]

if __name__=="__main__":
    MatrixVectMultiplyTast.run()

此代码运行./matrix.py < input.txt,其工作原理是矩阵按列存储在input.txt中,相应的矢量值位于行的末尾。

所以,下面的矩阵和向量:

enter image description here

表示为input.txt:

enter image description here

简而言之,我如何更自然地将矩阵和矢量存储在单独的文件中并将它们传递到MRJob中?

5 个答案:

答案 0 :(得分:3)

如果您需要针对另一个(或相同的row_i,row_j)数据集处理原始数据,您可以:

1)创建一个S3存储桶以存储数据副本。将此副本的位置传递给您的任务类,例如self.options.bucket和self.options.my_datafile_copy_location在下面的代码中。警告:不幸的是,似乎必须在处理之前将整个文件“下载”到任务机器上。如果连接停滞或加载时间过长,则此作业可能会失败。这是一些Python / MRJob代码来执行此操作。

将它放在mapper函数中:

d1 = line1.split('\t', 1)
v1, col1 = d1[0], d1[1]
conn = boto.connect_s3(aws_access_key_id=<AWS_ACCESS_KEY_ID>, aws_secret_access_key=<AWS_SECRET_ACCESS_KEY>)
bucket = conn.get_bucket(self.options.bucket)  # bucket = conn.get_bucket(MY_UNIQUE_BUCKET_NAME_AS_STRING)
data_copy = bucket.get_key(self.options.my_datafile_copy_location).get_contents_as_string().rstrip()
### CAVEAT: Needs to get the whole file before processing the rest.
for line2 in data_copy.split('\n'):
    d2 = line2.split('\t', 1)
    v2, col2 = d2[0], d2[1]
    ## Now, insert code to do any operations between v1 and v2 (or c1 and c2) here:
    yield <your output key, value pairs>
conn.close()

2)创建一个SimpleDB域,并将所有数据存储在那里。 在这里阅读boto和SimpleDB: http://code.google.com/p/boto/wiki/SimpleDbIntro

您的映射器代码如下所示:

dline = dline.strip()
d0 = dline.split('\t', 1)
v1, c1 = d0[0], d0[1]
sdb = boto.connect_sdb(aws_access_key_id=<AWS_ACCESS_KEY>, aws_secret_access_key=<AWS_SECRET_ACCESS_KEY>)
domain = sdb.get_domain(MY_DOMAIN_STRING_NAME)
for item in domain:
    v2, c2 = item.name, item['column']
    ## Now, insert code to do any operations between v1 and v2 (or c1 and c2) here:
    yield <your output key, value pairs>
sdb.close()

如果您拥有非常大量的数据,则第二个选项可能会表现得更好,因为它可以同时为每行数据而不是整个数据发出请求。请记住,SimpleDB值最多只能包含1024个字符,因此如果数据值超过此值,则可能需要通过某种方法进行压缩/解压缩。

答案 1 :(得分:2)

你的问题的实际答案是mrjob还不支持hadoop流连接模式,即读取map_input_file环境变量(暴露map.input.file属性)以确定你是哪种类型的文件根据其路径和/或名称进行处理。

如果您可以轻松地检测数据本身属于哪种类型,您仍然可以将其关闭,如本文所示:

http://allthingshadoop.com/2011/12/16/simple-hadoop-streaming-tutorial-using-joins-and-keys-with-python/

然而,这并不总是可能......

否则myjob看起来很棒,我希望他们将来可以为此添加支持。在那之前,这对我来说几乎是一个交易障碍。

答案 2 :(得分:2)

这是我使用多个输入并基于文件名在映射器阶段进行适当更改的方式。

亚军计划:

from mrjob.hadoop import *


#Define all arguments

os.environ['HADOOP_HOME'] = '/opt/cloudera/parcels/CDH/lib/hadoop/'
print "HADOOP HOME is now set to : %s" % (str(os.environ.get('HADOOP_HOME')))
job_running_time = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S')
hadoop_bin = '/usr/bin/hadoop'
mode = 'hadoop'
hs = HadoopFilesystem([hadoop_bin])

input_file_names = ["hdfs:///app/input_file1/","hdfs:///app/input_file2/"]

aargs = ['-r',mode,'--jobconf','mapred.job.name=JobName','--jobconf','mapred.reduce.tasks=3','--no-output','--hadoop-bin',hadoop_bin]
aargs.extend(input_file_names)
aargs.extend(['-o',output_dir])
print aargs
status_file = True

mr_job = MRJob(args=aargs)
with mr_job.make_runner() as runner:
    runner.run()
os.environ['HADOOP_HOME'] = ''
print "HADOOP HOME is now set to : %s" % (str(os.environ.get('HADOOP_HOME')))

MRJob类:

class MR_Job(MRJob):
    DEFAULT_OUTPUT_PROTOCOL = 'repr_value'
    def mapper(self, _, line):
    """
    This function reads lines from file.
    """
    try:
        #Need to clean email.
        input_file_name = get_jobconf_value('map.input.file').split('/')[-2]
                """
                Mapper code
                """
    except Exception, e:
        print e

    def reducer(self, email_id,visitor_id__date_time):
    try:
        """
                Reducer Code
                """
    except:
        pass


if __name__ == '__main__':
    MRV_Email.run()

答案 3 :(得分:1)

根据我的理解,除非你想利用亚马逊的Hadoop集群或Hadoop服务,否则你不会使用MrJob,即使该示例利用在本地文件上运行。

MrJob in principal使用“Hadoop streaming”提交作业。

这意味着从Hadoop指定为文件或文件夹的所有输入都将流式传输到映射器,后续结果将流式传输到reducer。所有映射器都获得一个输入片段,并认为所有输入都是相同的,因此它统一解析并处理每个数据片的键值。

从这种理解中得出,输入与映射器的示意图相同。只有可能包含两个不同的原理图数据的方法是将它们交织在同一个文件中,使映射器能够理解哪个是矢量数据,哪个是矩阵数据。

You are actually doing it already.

如果一条线是矩阵数据或矢量数据,你可以通过设置一些说明符来简单地改进它。一旦看到矢量数据,就会将前面的矩阵数据应用于它。

matrix, 1, 2, ...
matrix, 2, 4, ...
vector, 3, 4, ...
matrix, 1, 2, ...
.....

但是你提到的过程效果很好。您必须将所有原理图数据放在一个文件中。

但这仍有问题。当完整模式存在于一行并包含完整的单个处理单元时,K,V map reduce更有效。

根据我的理解,你已经正确地做了,但我猜Map-Reduce不适合这种数据。我希望有人能够进一步澄清这一点。

答案 4 :(得分:1)

MrJob Fundumentals状态:

您可以传递多个输入文件,这些文件与stdin混合(使用-字符):

$ python my_job.py input1.txt input2.txt - < input3.txt