【问题标题】:Hadoop: Outside of Eclipse List looses DataHadoop:Eclipse 列表之外的数据丢失
【发布时间】:2013-11-21 08:49:22
【问题描述】:

我编写了一个简单的 MapReduce 作业(基于 Word Count 示例)来获取文本文件中的总字数。我逐行浏览文件,在映射它之前我做了一些处理。除了在映射之前从行中删除某些单词之外,所有这些似乎都有效。

在开始工作之前,我从一个文件中读取了一个单词列表,在映射一行之前应该删除这些单词。我让程序在阅读后打印出单词列表,它工作正常。 问题是:一旦工作开始,我的包含单词的 ArrayList 似乎又是空的。有趣的是,它只发生在 eclipse (jar 文件)之外启动程序时,在 eclipse 中,单词被删除。 eclipse 之外的最终结果是 1320 万字,尽管总共应该是 1340 万字(不从列表中删除字)。在 Eclipse 中,结果应该是 840 万。

这是为什么呢?非常感谢您的帮助!

这是我的代码:

import java.io.*;
import java.util.*; 

import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.*; 
import org.apache.hadoop.conf.*; 
import org.apache.hadoop.io.*; 
import org.apache.hadoop.io.file.tfile.TFile.Reader.Scanner;
import org.apache.hadoop.mapred.*; 
import org.apache.hadoop.util.*; 

public class WordCount { 

    public static class Map extends MapReduceBase implements Mapper<LongWritable, Text,  NullWritable, IntWritable> { 

        private final static IntWritable one = new IntWritable(1); 
        private final static NullWritable nullKey = NullWritable.get();

        public void map(LongWritable key, Text value, OutputCollector< NullWritable, IntWritable> output, Reporter reporter) throws IOException { 

            String processedline = LineProcessor.processLine(value.toString());

            StringTokenizer tokenizer = new StringTokenizer(processedline); 
            while (tokenizer.hasMoreTokens()) { 
                tokenizer.nextToken();
                output.collect(nullKey, one); 
            } 
        }  

    } 

    public static class Reduce extends MapReduceBase implements Reducer<NullWritable, IntWritable, NullWritable, IntWritable> { 

        private final static NullWritable nullKey = NullWritable.get();

        public void reduce(NullWritable key, Iterator<IntWritable> values, OutputCollector<NullWritable, IntWritable> output, Reporter reporter) throws IOException { 

            int sum = 0; 
            while (values.hasNext()) { 
                sum += values.next().get(); 
            } 
            output.collect(nullKey, new IntWritable(sum)); 
        }

    } 

    public static class LineProcessor{
        public static ArrayList<String> stopWordsList = new ArrayList<String>();

        public static void initializeStopWords() throws IOException{
            Path stop_words = new Path("/user/ds2013/stop_words/english_stop_list.txt");
            FileSystem fs = FileSystem.get(new Configuration());
            BufferedReader br = new BufferedReader(new InputStreamReader(fs.open(stop_words)));
            String stopWord;
            stopWord = br.readLine();

            while (stopWord != null){
                //addToStopWords
                stopWordsList.add(stopWord);
                stopWord = br.readLine();
            }
        }

        public static String processLine(String line) {
            line = line.toLowerCase();
            //delete some punctuation
            char[] remove = {'.', ',','"'};
            for (char c : remove) {
                line = line.replace(""+c, "");
            }
            //Replace "-" with Space
            line = line.replace("-", " ");

            //delete stop Words
            StringTokenizer tokenizer = new StringTokenizer(line); 
            String nextWord = tokenizer.nextToken();
            while (tokenizer.hasMoreTokens()) {     
                if(stopWordsList.contains(nextWord)){
                    line = line.replace(nextWord, "");
                }
                nextWord = tokenizer.nextToken();
            } 

            return line;
        }
    }

    public static void main(String[] args) throws Exception { 
        JobConf conf = new JobConf(WordCount.class); 
        conf.setJobName("wordcount"); 
        conf.setMapOutputKeyClass(NullWritable.class);
        conf.setMapOutputValueClass(IntWritable.class);
        conf.setOutputKeyClass(NullWritable.class);
        conf.setOutputValueClass(IntWritable.class);

        conf.setMapperClass(Map.class); 
        conf.setCombinerClass(Reduce.class); 
        conf.setReducerClass(Reduce.class); 

        conf.setInputFormat(TextInputFormat.class); 
        conf.setOutputFormat(TextOutputFormat.class);
        //initialize List of words that should be deletet
        LineProcessor.initializeStopWords();

        //Directories

        FileInputFormat.setInputPaths(conf, new Path("/user/ds2013/data/plot_summaries.txt"));


        Path outputDir = new Path( args[0] );
        //delete output folder if it already exists
        FileSystem fs = FileSystem.get(conf);
        fs.delete(outputDir, true);
        FileOutputFormat.setOutputPath(conf, outputDir);


        JobClient.runJob(conf); 

    } 
}

【问题讨论】:

  • 你所说的“在eclipse之外”是什么意思,你是在真正的集群中启动它吗?
  • 我的意思是我将它导出为一个 jar 并使用类似“hadoop jar wordCount.jar packageName.WordCount /data/wordcount”这样的命令启动它,它在虚拟机中都是本地的。

标签: java eclipse list hadoop mapreduce


【解决方案1】:

如果您通过命令行提交作业,它将为此创建一个客户端进程。因此,您在 main 方法中进行的初始化:

LineProcessor.initializeStopWords();

在一个完全不同的进程中运行。您通常将此初始化内容移动到您可以覆盖的映射器中的设置函数中(在您使用的旧 API 中):

public void configure(JobConf job) {
   LineProcessor.initializeStopWords();
}

或者在较新的 API 中是:

public void setup(Context context) {
   LineProcessor.initializeStopWords();
}

【讨论】:

  • 非常感谢,这似乎是有道理的。我一回家就试试这个。因此,如果我向映射器类添加一个配置函数,我在该函数中所做的一切(即使 ArrayList 在映射器类之外)都会按预期工作,因为它在同一个进程中?并且此配置函数将始终在实际映射函数之前运行(并且每个作业仅运行一次,因此它不会初始化列表 1300 万次)?
  • 是的,它将在每个映射器进程(hadoop 语言中的任务)和映射调用之前运行一次。
  • 好的,我刚回到家,试了一下,效果很好。非常感谢:-)
猜你喜欢
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
  • 2012-11-13
相关资源
最近更新 更多