从hadoop中的map / reduce任务中检索已更改的变量

时间:2012-07-16 17:42:45

标签: hadoop global-variables

我有一个全局布尔变量,它控制main函数中的循环以确定是否重新开始。如果满足条件,则在reduce中将变量设置为true。然后在主要情况下,如果满足条件,则再次运行整个程序。这适用于一台机器,但是当我尝试在亚马逊EC2上运行它时,它不会循环。

3 个答案:

答案 0 :(得分:1)

问题是,在EC2上,您运行的是真正的分布式模式(多台机器,每台机器运行自己的JVM),而在您的机器上,您以独立模式运行(仅使用1个JVM)。

当您在计算机上运行作业时,hadoop框架在同一JVM中运行客户端(所谓的驱动程序),map任务和reduce任务。因此,您的reduce函数和main将能够使用SAME全局变量。 (作为旁注,我认为这个全局变量应该是静态的,因为hadoop框架可能会为客户端创建多个对象,映射,减少执行。如果你没有使它静止,它仍然可以在你的机器上工作,这意味着它使用相同的对象)。

在EC2上运行作业时,您将在不同的JVM中运行客户端,映射任务和reduce任务。因此,减速器将修改"全局"驻留在当前JVM中的对象的变量,因此运行客户端的JVM(在其JVM中的对象中拥有它自己的全局变量版本)不会看到reducer对其进行的修改"全球"变量

请注意全球各地的报价。它们表示变量不像您预期​​的那样全局。

您可以通过在文件中写入该变量的值并将该文件放在分布式缓存中,或者通过在变量的输出中写入变量,将变量从reducer传递回驱动程序(主类)作业(part-r-xxxx文件),以防您将其与实际输出/有效负载分开。

在这两种情况下,驱动程序都可以从缓存中检索文件,也可以从作业的输出目录中检索输出文件。读入变量的值,并在此基础上做出决定。

如果您想计算减速器达到特定状态的数量。您可以使用用户定义的计数器(当达到该状态时将由每个reducer递增),您可以在映射器中解释它。可以使用Mapper.Context / Reducer.Context的getCounter()方法通过名称访问计数器

答案 1 :(得分:0)

Razvan提到的map reduce工作中不能有全局变量,因为你的代码在许多机器(分布式)上并行运行。服务器A上的减少作业(并且必须是MapReduce)完全独立于机器B上运行的代码。在重新启动之前,您必须等待作业完成(成功与否)。如果您可以等待完成,可以在配置中设置变量,或者使用计数器作为“全局变量”,并在作业停止时引用它。如果你正在使用HBase,你可以在HBase中设置一个值,并在你想要的时候读取它的作业。

你的情况可能会使HBase有点矫枉过正,除非你已经设置好了。

要设置配置,请在主驱动程序功能中执行以下操作:

conf.set("variableName",variableValue);

要在Mapper或Reducer中访问配置:

Configuration conf = context.getConfiguration();
String variableValue = conf.get("variableName");

请注意,每个映射器或缩减器都不会对另一个映射器或缩减器对变量所做的任何更改视而不见。我不确定你是否想在mapper或reducers中修改conf变量 - 这可能不是最好的做法。

对于计数器,您可以在mapper或reducer中执行以下操作(以1为增量计数器):

context.getCounter("counterName").increment(new Long(1));

完成MR工作后,您可以通过以下方式引用计数器:

Counters counters = job.getCounters();
Counter counter = counters.findCounter("counterName");
long cntVal = counter.getValue();

同样,只有在MR作业完成后才能信任您的计数器值,而不是在MR作业运行时。

答案 2 :(得分:0)

我最后用计数器来做这件事并不是很漂亮,但它确实有效。我创建了两个变量cnt和cnt1。如果符合条件,我使用计数器增加。 cnt保存上次作业循环时的计数cnt1在作业后更新,如果它们相同则不再循环。这最终会在一次额外的时间内运行所有作业,但它会提供正确的输出。

感谢您的帮助。