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



我有一个全局布尔变量,它控制主函数中的一个循环,以确定是否重新启动。决策是在reduce中做出的,如果满足条件,则变量设置为true。然后,如果满足条件,它将再次运行整个程序。这在一台机器上有效,但当我试图在Amazons EC2上运行它时,它不会循环通过。

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

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

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

注意global周围的引号。它们表示变量并不像你期望的那样具有全局性

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

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

如果您想计算有多少减速器达到特定状态。您可以使用用户定义的计数器(当达到该状态时,每个减少器都会增加计数器),并可以在映射器中对其进行解释。可以使用Mapper.Context/Reducer.Context 的getCounter()方法通过其名称访问计数器

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

你的情况可能会让HBase有点过头,除非你已经设置好了。

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

conf.set("variableName",variableValue);

访问映射器或还原器中的配置:

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

请注意,每个映射器或还原器都将对另一个映射器或缩减器对变量所做的任何更改视而不见。我不确定您是否想在映射器或还原器中修改conf变量——这可能不是最佳实践。

对于计数器,您可以在映射器或还原器中执行以下操作(将计数器递增1):

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

当你的MR工作完成后,你可以通过以下方式参考计数器:

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

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

我最终用计数器做了这件事——它不那么漂亮,但它很管用。我创建了两个变量cnt和cnt1。如果满足条件,我使用计数器递增。cnt保存上次循环作业后的计数cnt1在作业后更新,如果它们相同,则不会再次循环。这最终会使所有作业多运行一次,但会给出正确的输出。

谢谢你的帮助。

相关内容

  • 没有找到相关文章

最新更新