MapReduce中的counter

本文详细解释了如何在Hadoop MapReduce中使用Counter进行数据计数,包括Counter的定义、增加计数、获取计数以及输出计数等关键步骤。同时介绍了Counter的本地化名字和CounterGroup的概念,以及如何通过配置文件自定义Counter的名字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

当我们定义一个Counter时,我们首先要定义一枚举类型:

[html]  view plain copy print ?
  1. public static enum MY_COUNTER{  
  2.   CORRUPTED_DATA_COUNTER,  
  3.   NORMAL_DATA_COUNTER  
  4. };  

  然后,我们就可以在mapper或reducer里面增加它的值:

[html]  view plain copy print ?
  1. context.getCounter(MY_COUNTER.CORRUPTED_DATA_COUNTER).increment(1);  
  我们在第(一)篇讲InputFormat时,我们有看到Mapper.class中的Context类是继承于MapContext类的,而MapContext又继承于TaskInputOutputContext,我们可以从TaskInputOutputContext的getCounter()方法看见,这个方法实际上是调用了StatusReporter的getCounter()方法,StatusReporter在后面谈到。

  接着,我们在提交job,waitForCompletion()方法等待job执行完后,就可以通过

[html]  view plain copy print ?
  1. Counters counters = job.getCounters();  
  2. Counter counter = counters.findCounter(MYCOUNTER.CORRUPTED_DATA_COUNTER);  
  3. System.out.println(counter.getValue());  

  这样就将我们想要输出的计数器输出来。如果在执行前企图输出,则会报:java.lang.IllegalStateException: Job in state DEFINE instead of RUNNING。


  Counter对应我们写的enum类型中的一个枚举常量,比如MY_COUNTER.CORRUTED_DATA_COUNTER,它由name,displayName和value表示,value是Counter当前计数值。Counter、CounterGroup和Counters都实现了Writable接口,由于Counter是全局的,所以它们的读写方法都是synchronized方法,以保证线程安全。


  CounterGroup对应我们写的enum类型,比如MY_COUNTER。CounterGroup有name,displayName,TreeMap类型的counters,以及一个ResourceBoundle bundle。counters存放的是enum里面的所有枚举常量对应的Counter。而bundle是用来本地化Counter的名字的。举个例子:src\mapred\org\apache\hadoop\mapred下有一个JobInProgress_Counter.properties文件,内容是这样的:

[html]  view plain copy print ?
  1. # ResourceBundle properties file for job-level counters  
  2.   
  3. CounterGroupName=                  Job Counters   
  4.   
  5. NUM_FAILED_MAPS.name=              Failed map tasks  
  6. NUM_FAILED_REDUCES.name=           Failed reduce tasks  
  7. TOTAL_LAUNCHED_MAPS.name=          Launched map tasks  
  8. TOTAL_LAUNCHED_REDUCES.name=       Launched reduce tasks  
  9. OTHER_LOCAL_MAPS.name=             Other local map tasks  
  10. DATA_LOCAL_MAPS.name=              Data-local map tasks  
  11. RACK_LOCAL_MAPS.name=              Rack-local map tasks  
  12. FALLOW_SLOTS_MILLIS_MAPS.name=     Total time spent by all maps waiting after reserving slots (ms)  
  13. FALLOW_SLOTS_MILLIS_REDUCES.name=  Total time spent by all reduces waiting after reserving slots (ms)  
它存放的是job级别的counters的本地化名字。形式是name = displayName。

这样,我们就可以每次利用name从改文件中读取displayName,使得当我们改变这个properties文件中的某个displayName的时候,不需要改动程序。


   Counters是一个Job的Counter最后的汇聚地,在分析Job类得时候,我们看到Job.getCounters()方法是用RunningJob得到的,而RunningJob是获取作业情况的一组接口。因为Counters会最终被JobTracker收集,要不断从TaskTracker收集并更新,因此它包含一个缓冲最近读的Counter的cache来进行优化,它还有一个存储Job的所有Counter的TreeMap。当我们使用findCounter((Enum<?> key)方法查找Counter时,它会先在cache中查找,如果没有找到,则会从TreeMap中查找并放入cache中。Counters还实现了Iterable接口,以支持对Counters的遍历。另外还提供了increase所有Counter的方法incrAllCounters()。

MapReduce程序中,计数器是一种用于跟踪作业运行时信息的机制。我们可以通过计数器来记录某个特定事件发生的次数或者某个特定状态的数量。例如,我们可以使用计数器来记录程序中处理的行数、错误的数量、跳过的记录数等等。 MapReduce框架提供了两种类型的计数器:任务计数器和作业计数器。任务计数器是每个MapReduce任务独有的计数器,而作业计数器是整个作业共享的计数器。 任务计数器可以通过TaskAttemptContext对象的getCounter()方法获取。TaskAttemptContextMapReduce任务中的一个上下文对象,该对象包含了任务的所有信息,包括计数器。任务计数器可以用于跟踪任务内部的事件或状态。 作业计数器可以通过JobContext对象的getCounter()方法获取。JobContext是整个MapReduce作业的上下文对象,该对象包含了作业的所有信息,包括计数器。作业计数器可以用于跟踪整个作业的事件或状态。 计数器可以通过以下方式进行操作: 1. 增加计数器的值:通过调用计数器的increment()方法,可以将计数器的值增加指定的数量。 2. 获取计数器的值:通过调用计数器的getValue()方法,可以获取计数器的当前值。 3. 设置计数器的值:通过调用计数器的setValue()方法,可以设置计数器的值。 在MapReduce程序中,计数器通常用于跟踪任务或作业的进度,以及记录一些重要的事件或状态。使用计数器可以帮助我们更好地理解程序的运行情况,以便对程序进行优化和调试。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值