Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 访问映射器';从减速器上拆下计数器_Java_Hadoop - Fatal编程技术网

Java 访问映射器';从减速器上拆下计数器

Java 访问映射器';从减速器上拆下计数器,java,hadoop,Java,Hadoop,我需要从减速器中的映射器访问计数器。这可能吗?如果是的话,是如何做到的 例如: 我的绘图程序是: public class CounterMapper extends Mapper<Text,Text,Text,Text> { static enum TestCounters { TEST } @Override protected void map(Text key, Text value, Context context)

我需要从减速器中的映射器访问计数器。这可能吗?如果是的话,是如何做到的

例如: 我的绘图程序是:

public class CounterMapper extends Mapper<Text,Text,Text,Text> {

    static enum TestCounters { TEST }

    @Override
    protected void map(Text key, Text value, Context context)
                    throws IOException, InterruptedException {
        context.getCounter(TestCounters.TEST).increment(1);
        context.write(key, value);
    }
}
公共类计数器映射器扩展映射器{
静态枚举测试计数器{TEST}
@凌驾
受保护的空映射(文本键、文本值、上下文)
抛出IOException、InterruptedException{
getCounter(TestCounters.TEST).increment(1);
编写(键、值);
}
}
我的减速机是

public class CounterReducer extends Reducer<Text,Text,Text,LongWritable> {

    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context)
                        throws IOException, InterruptedException {
        Counter counter = context.getCounter(CounterMapper.TestCounters.TEST);
        long counterValue = counter.getValue();
        context.write(key, new LongWritable(counterValue));
    }
}
公共类计数器减速机扩展减速机{
@凌驾
受保护的void reduce(文本键、Iterable值、上下文)
抛出IOException、InterruptedException{
计数器计数器=context.getCounter(CounterMapper.TestCounters.TEST);
长计数器值=counter.getValue();
write(key,新的LongWritable(counterValue));
}
}
计数器值始终为0。
我做错了什么,还是这根本不可能?

map/reduce的整个要点是并行化作业。将有许多唯一的映射器/还原器,因此该值无论如何都不正确,除非运行映射/还原对

他们有一个单词计数示例:


您可以将context.write(字,一)更改为context.write(行,一)

全局计数器值永远不会广播回每个映射器或还原器。如果希望还原程序可以使用映射程序记录的#,则需要依赖一些外部机制来完成此操作。

在还原程序的配置(JobConf)中,可以使用JobConf对象查找还原程序自己的作业id。这样,您的reducer可以创建自己的JobClient(即到jobtracker的连接),并查询此作业(或任何与此相关的作业)的计数器

现在,您可以在reduce()方法内部使用mapperCounter

你真的需要在这里试一试。我正在使用旧的API,但适应新的API应该不难


请注意,映射器的计数器都应该在任何减速机启动之前完成,因此与Justin Thomas的评论相反,我相信您应该获得准确的值(只要减速机不增加相同的计数器!)

在新API上实现了Jeff G的解决方案:

    @Override
    public void setup(Context context) throws IOException, InterruptedException{
        Configuration conf = context.getConfiguration();
        Cluster cluster = new Cluster(conf);
        Job currentJob = cluster.getJob(context.getJobID());
        mapperCounter = currentJob.getCounters().findCounter(COUNTER_NAME).getValue();  
    }
我问了,但我还没有解决我的问题。然而,我想到了另一个解决办法。在映射器中,字数是计数的,可以在映射器末尾运行的清除函数中使用最小键(以便该值位于head中)将其写入中间输出。在reducer中,通过在head中添加值来计算字数。下面提供了示例代码及其部分输出

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

import java.io.IOException;
import java.util.StringTokenizer;

/**
 * Created by tolga on 1/26/16.
 */
public class WordCount {
    static enum TestCounters { TEST }
    public static class Map extends Mapper<Object, Text, Text, LongWritable> {
        private final static LongWritable one = new LongWritable(1);
        private Text word = new Text();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            StringTokenizer tokenizer = new StringTokenizer(line);
            while (tokenizer.hasMoreTokens()) {
                word.set(tokenizer.nextToken());
                context.write(word, one);
                context.getCounter(TestCounters.TEST).increment(1);
            }
        }

        @Override
        protected void cleanup(Context context) throws IOException, InterruptedException {
            context.write(new Text("!"),new LongWritable(context.getCounter(TestCounters.TEST).getValue()));
        }
    }

    public static class Reduce extends Reducer<Text, LongWritable, Text, LongWritable> {

        public void reduce(Text key, Iterable<LongWritable> values, Context context)
                throws IOException, InterruptedException {
            int sum = 0;
            for (LongWritable val : values) {
                sum += val.get();
            }
            context.write(key, new LongWritable(sum));
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();

        Job job = new Job(conf, "WordCount");
        job.setJarByClass(WordCount.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);

        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        job.waitForCompletion(true);
    }
}
中间输出

**!	33**
2008	1
行动1
安卡拉,1
基金会1
It 1
想法1
特古特1号
特古特1号
Turgut 1
伊扎基答案的改进

findCounter(计数器名称)
不再受支持-

调用计数器时,指定组名称。e、 g

context.getCounter("com.example.mycode", "MY_COUNTER").increment(1);
然后


还有一点很重要,如果计数器不存在,它将用值0初始化计数器。

作业跟踪器跟踪计数器。还原程序中不提供映射程序中的计数器,这似乎与直觉相反,但在
Hadoop
还原程序中,还原程序可以在所有映射程序完成之前开始执行。在这种情况下,计数器的值可以在减速机中的不同时间读取。要了解还原程序如何在映射程序完成执行之前启动,请访问以下帖子:@abhinavkulkarni实际上,只有还原程序的洗牌阶段才能在所有映射程序启动之前启动,这与计数器无关。因此,当reducer的reduce阶段开始时,所有映射器计数器都是正确的。在同一篇文章中:“另一方面,排序和减少只能在所有映射器都完成后启动。”我尝试了这一点,但在下面的行mapperCounter=currentJob.getCounters().findCounter(COUNTER_NAME)中出现了java空点异常错误,在该行中,我用我的自定义计数器替换了COUNTER_NAME。看起来
cluster.getJob(context.getJobID())
在hadoop的独立操作中不起作用。在单节点群集模式下运行时,这对我有效。您从何处导入
Cluster
?Intellij IDEA建议我导入
org.apache.commons.math.stat.clustering.Cluster
,而此导入不接受`配置作为构造函数的参数彼得。
Turgut Özal University is a private university located in Ankara, Turkey. It was established in 2008 by the Turgut Özal Thought and Action Foundation and is named after former Turkish president Turgut Özal.
@Override
public void setup(Context context) throws IOException, InterruptedException{
    Configuration conf = context.getConfiguration();
    Cluster cluster = new Cluster(conf);
    Job currentJob = cluster.getJob(context.getJobID());
    mapperCounter = currentJob.getCounters().findCounter(GROUP_NAME, COUNTER_NAME).getValue();  
}
context.getCounter("com.example.mycode", "MY_COUNTER").increment(1);
mapperCounter = currentJob.getCounters().findCounter("com.example.mycode", "MY_COUNTER").getValue();