【问题标题】:MapReduce - reducer does not combine keysMapReduce - reducer 不组合键
【发布时间】:2015-06-06 07:34:27
【问题描述】:

我有一个简单的 map reduce 工作,我正在构建反向索引。

我的映射器工作正常(我检查过了)并输出了 word 和 docID:TFIDF 值的密钥对:

Mapper(仅显示输出):

context.write(new IntWritable(wordIndex), new Text(index + ":" + tfidf));

reducer 唯一的工作就是组合这些值。这是我的实现:

public static class IndexerReducer extends Reducer<Text, IntWritable, IntWritable, Text>
    {
        public void reduce(IntWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException
        {

            StringBuilder sb = new StringBuilder();

            for (Text value : values)
            {
                sb.append(value.toString() + " ");
            }

            context.write(key, new Text(sb.toString()));
        }
    }

但是,它没有组合任何东西,输出看起来与映射器基本相同。尽管 reducer 应该将它们组合在一起,但输出中有具有相同键的行 - 基本上输出文件中的所有键在使用 reducer 时都应该是唯一的,对吧?

这是我的 reducer 输出的示例(请注意,这是简化示例):

1 15:2.1
1 13:4.3
2 9:9.3
2 43:7.9
etc

我预料到了:

1 15:2.1 13:4.3
2 9:9.3 43:7.9

为了完整起见,我将run方法包括在内:

@Override
    public int run(String[] arguments) throws Exception {
        ArgumentParser parser = new ArgumentParser("TextPreprocessor");

        parser.addArgument("input", true, true, "specify input directory");
        parser.addArgument("output", true, true, "specify output directory");

        parser.parseAndCheck(arguments);

        Path inputPath = new Path(parser.getString("input"));
        Path outputDir = new Path(parser.getString("output"));

        // Create configuration.
        Configuration conf = getConf();

        // add distributed file with vocabulary
        DistributedCache
                .addCacheFile(new URI("/user/myslima3/vocab.txt"), conf);

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

        // Setup MapReduce.
        job.setMapperClass(IndexerMapper.class);
        job.setReducerClass(IndexerReducer.class);

        // Sort the output words in reversed order.
        job.setSortComparatorClass(WordCountComparator.class);


        job.setNumReduceTasks(1);

        // Specify (key, value).
        job.setMapOutputKeyClass(IntWritable.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(IntWritable.class);
        job.setOutputValueClass(Text.class);

        // Input.
        FileInputFormat.addInputPath(job, inputPath);
        job.setInputFormatClass(TextInputFormat.class);

        // Output.
        FileOutputFormat.setOutputPath(job, outputDir);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileSystem hdfs = FileSystem.get(conf);

        // Delete output directory (if exists).
        if (hdfs.exists(outputDir))
            hdfs.delete(outputDir, true);

        // Execute the job.
        return job.waitForCompletion(true) ? 0 : 1;
    }

我会很高兴任何关于正在发生的事情的提示。我是地图减少的新手。感谢您提供任何调试提示!

【问题讨论】:

    标签: java hadoop mapreduce


    【解决方案1】:

    始终使用@Override 注释。

    你定义了

    public static class IndexerReducer extends Reducer<Text, IntWritable, IntWritable, Text>
    

    那么你的reduce方法一定是这样的

    @Override
    public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException
    

    【讨论】:

    • 有意思,没想到。我的 IDE 不允许我这样做(它会产生异常:Indexer.IndexerReducer 类型的方法 reduce(IntWritable, Iterable, Reducer.Context) 必须覆盖或实现超类型方法
    • 没错,因为它是错误的。请注意,我为您交换了 keyvalues 类型。
    • 但是我传递给 reducer 的那对是 所以 IntWritable 应该是关键.. 对吧?
    • 好的,我在两条线上都交换了它(甚至是减速器),现在它可以让我覆盖 - 我会尝试运行它并接受它是否有效
    • 否,输入 = Text, IntWritable,输出 = IntWritable, Text。请阅读文档:)
    【解决方案2】:

    @context 不是 org.apache.hadoop.mapreduce.Reducer.Context 类型。 我们的 Reducer 有我们自己的内部类类型的 Context。 所以不要使用“org.apache.hadoop.mapreduce.Reducer.Context”,只需使用“Context” 这将确保可以添加 @Override 以减少功能而不会出错。

    【讨论】:

      猜你喜欢
      • 2013-04-28
      • 2019-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 1970-01-01
      相关资源
      最近更新 更多