我正在使用MapReduce(只是map,真的)分四个阶段完成数据处理任务。每个阶段都是一个MapReduce作业。我需要它们按顺序运行,也就是说,在第1阶段完成之前不要启动阶段2,等等。有没有人有这样的经验可以共享?
理想情况下,我们会在一夜之间完成这个4个工作序列,所以要做到这一点 cron-able也是一件好事。
谢谢
答案 0 :(得分:1)
正如Daniel所提到的,appengine-pipeline库旨在解决这个问题。我在“实现您自己的管道作业”部分下一起查看mapreduce作业in this blog post。
为方便起见,我会在此处粘贴相关部分:
既然我们知道如何启动预定义的MapreducePipeline,那么让我们来看看如何实现和运行我们自己的自定义管道作业。管道库提供了一个低级库,用于在appengine中启动任意分布式计算作业,但是,目前,我们将专门讨论如何使用它来帮助我们将mapreduce作业链接在一起。让我们扩展前面的例子,也输出一个字符和ID的反向索引。
首先,我们定义父管道作业。
class ChainMapReducePipeline(mapreduce.base_handler.PipelineBase):
def run(self):
deduped_blob_key = (
yield mapreduce.mapreduce_pipeline.MapreducePipeline(
"test_combiner",
"main.map",
"main.reduce",
"mapreduce.input_readers.RandomStringInputReader",
"mapreduce.output_writers.BlobstoreOutputWriter",
combiner_spec="main.combine",
mapper_params={
"string_length": 1,
"count": 500,
},
reducer_params={
"mime_type": "text/plain",
},
shards=16))
char_to_id_index_blob_key = (
yield mapreduce.mapreduce_pipeline.MapreducePipeline(
"test_chain",
"main.map2",
"main.reduce2",
"mapreduce.input_readers.BlobstoreLineInputReader",
"mapreduce.output_writers.BlobstoreOutputWriter",
# Pass output from first job as input to second job
mapper_params=(yield BlobKeys(deduped_blob_key)),
reducer_params={
"mime_type": "text/plain",
},
shards=4))
这将启动与第一个示例相同的作业,从该作业获取输出,并将其提供给第二个作业,从而反转每个条目。请注意,第一个管道产量的结果将传递给第二个作业的mapper_params。管道库使用magic来检测第二个管道是否依赖于第一个管道完成,并且在deduped_blob_key解析之前不会启动它。
接下来,我必须创建BlobKeys帮助程序类。起初,我认为这不是必要的,因为我可以做到:
mapper_params={"blob_keys": deduped_blob_key},
但是,由于两个原因,这不起作用。第一个是“发电机管道不能直接访问它产生的子管道的输出”。上面的代码将要求生成器管道使用第一个作业的输出创建临时dict对象,这是不允许的。第二个是BlobstoreOutputWriter返回的字符串格式为“/ blobstore /”,但BlobstoreLineInputReader只需要“”。为了解决这些问题,我做了一个小帮手BlobKeys类。您会发现自己为许多工作执行此操作,并且管道库甚至包含一组常见的包装器,但它们不能在MapreducePipeline框架内工作,我将在本节的底部讨论。
class BlobKeys(third_party.mapreduce.base_handler.PipelineBase):
"""Returns a dictionary with the supplied keyword arguments."""
def run(self, keys):
# Remove the key from a string in this format:
# /blobstore/<key>
return {
"blob_keys": [k.split("/")[-1] for k in keys]
}
以下是map2和reduce2函数的代码:
def map2(data):
# BlobstoreLineInputReader.next() returns a tuple
start_position, line = data
# Split input based on previous reduce() output format
elements = line.split(" - ")
random_id = elements[0]
char = elements[1]
# Swap 'em
yield (char, random_id)
def reduce2(key, values):
# Create the reverse index entry
yield "%s - %s\n" % (key, ",".join(values))
答案 1 :(得分:0)
我不熟悉google-app-engine,但是你不能把所有的工作配置放在一个主程序中,然后按顺序运行它们吗?像下面这样的东西?我认为这适用于普通的map-reduce程序,所以如果google-app-engine代码没有太大的不同,它应该可以正常工作。
Configuration conf1 = getConf();
Configuration conf2 = getConf();
Configuration conf3 = getConf();
Configuration conf4 = getConf();
//whatever configuration you do for the jobs
Job job1 = new Job(conf1,"name1");
Job job2 = new Job(conf2,"name2");
Job job3 = new Job(conf3,"name3");
Job job4 = new Job(conf4,"name4");
//setup for the jobs here
job1.waitForCompletion(true);
job2.waitForCompletion(true);
job3.waitForCompletion(true);
job4.waitForCompletion(true);
答案 2 :(得分:0)
你需要appengine-pipeline项目,这正是为了这个目的。