Hadoop大數據平臺入門——第一個小程序WordCount

首先我們需要安裝Hadoop,並對Hadoop進行配置。這裏我們就不贅述了,詳情看這篇博客:Hadoop安裝配置

值得注意的是,配置的時候,需要給Hadoop權限才能正確執行。最簡單的辦法就是講hadoop以及其目錄下所有文件都歸在一個組中。

chown -R  hadoop:hadoop hadoop文件夾
就可以了。


配置完成之後,我們我們還需要什麼?

1.需要在HDFS中保存有文件。

2.需要一個程序jar包,我們前面說過,JobTracker接收jar包就會分解job爲mapTask和reduceTask。mapTask會讀取HDFS中的文件來執行。


我們來看目標。

我們輸入兩個文件,file1和file2。交給hadoop執行之後,會返回file1和file2文件中的單詞的計數。

我們說過,hadoop返回的是<key,value>的鍵值對的形式。

所以結果如下:也就是把單詞以及單詞的個數返回

school 1
hello  3
world 2
...


所以我們首先創建兩個文件:

file1和file2。

隨便填點東西在裏面,文件中的內容是用來計數。單詞之間用空格分隔,當然這是不一定的,如何區分單詞是在後面jar包中的map程序中分辨的。

我們寫好了這兩個文件之後,要將文件提交到HDFS中。如何提交呢?

提交之前,首先要確保hadoop已經運行起來了,查看jps可以看到hadoop的進程。

首先我們在hadoop的HDFS中創建一個文件夾。

hdfs dfs -mkdir input_wordcount
這樣就可以在HDFS根目錄下創建一個input_wordcount的文件夾。

其實Hadoop的HDFS命令行非常接近Shell,只需要使用hdfs dfs -後面寫上shell命令就可以對應執操作HDFS文件系統了。

例如:hdfs dfs -ls查看根目錄下的文件。

創建文件夾之後,我們就可以提交我們寫的兩個file文件。

hdfs dfs -put input/* input_wordcount
這裏我兩個file文件都放在input目錄下,所以直接使用正則表達式都提交上去即可,提交到input_wordcount文件夾下。然後我們查看input_wordcount文件夾下的文件,查看是否提交完成。

hdfs dfs -ls input_wordcount
Found 4 items
-rw-r--r--   3 haoye supergroup         71 2017-05-06 20:34 input_wordcount/file1
-rw-r--r--   3 haoye supergroup          0 2017-05-06 20:34 input_wordcount/file1~
-rw-r--r--   3 haoye supergroup         74 2017-05-06 20:34 input_wordcount/file2
-rw-r--r--   3 haoye supergroup          0 2017-05-06 20:34 input_wordcount/file2~
提交成功了。


第一個要求完成了,接下來我們就需要一個程序jar包。

打開IDE工具。創建一個java程序,我在這裏創建一個maven項目。

首先我們需要導入依賴包:

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.6.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-mapreduce-client-core -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-core</artifactId>
    <version>2.6.0</version>
</dependency>
然後我們創建一個WordCount類。

在這個類裏,首先我們要創建一個Map方法,需要繼承Mapper類:

public static class WordCountMap extends
        Mapper<LongWritable, Text, Text, IntWritable> {
    private final IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        String line = value.toString();
        StringTokenizer token = new StringTokenizer(line);
        while (token.hasMoreTokens()) {
            word.set(token.nextToken());
            context.write(word, one);
        }
    }
}
Mapper<LongWritable, Text, Text, IntWritable>是什麼意思呢?

前面兩個類參數是輸入,後面兩個是輸出。

也就是WordCOuntMap方法接收LongWritable,Text的參數,返回<Text, IntWriatable>鍵值對。

需要重寫map方法,可以看到Context對象即爲返回結果,內部其實是<Text, IntWriatable>鍵值對。

這裏需要注意的是,value的值,value默認是一行數據,你文件中有多少行,map函數就會被調用多少次。

這我們就看懂了吧,首先拿到一行的數據,使用StringTokenizer根據空格分割字符串,得到token。遍歷token並寫入context中返回即可。


然後我們需要編寫reduce方法:同樣的,reduce方法繼承reduce類。

public static class WordCountReduce extends
        Reducer<Text, IntWritable, Text, IntWritable> {
    public void reduce(Text key, Iterable<IntWritable> values,
                       Context context) throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val : values) {
            sum += val.get();
        }
        context.write(key, new IntWritable(sum));
    }
}
wordCountReduce方法接收<Text, IntWritable>鍵值對,將鍵值對組合起來,結果寫入另外一個鍵值對中,返回即可。

其中最重要是重寫reduce方法,同樣的context也是返回的結果。

這裏需要注意的是,reduce方法是什麼時候調用的呢?是在所有mapTask都被執行完成之後,reduceTask啓動了才調用。

所有reduce方法中接收到的是所有map返回的參數。所以我們簡單的求和寫入context中就可以了。


最後我們編寫main方法作爲入口,調用兩個函數。

public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    Job job = new Job(conf);
    job.setJarByClass(WordCount.class);
    job.setJobName("wordcount");
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    job.setMapperClass(WordCountMap.class);
    job.setReducerClass(WordCountReduce.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);
}
這裏我們主要是告訴JobTracker,告訴他去調用什麼就可以了。

類都編寫好了之後`,我們需要的是jar包,所以我們將程序打包爲jar包。


拿到jar包之後,我們需要將jar包作爲作業提交給Hadoop執行。怎麼做呢?

hadoop jar WordCount.jar WordCount input_wordcount output_wordcount
hadoop jar WordCount.jar WordCount這裏提交jar包,並且告訴主類在哪。
後面兩個都是我們自定義的參數了。會在main中獲取到,即輸入參數爲input_wordcount。輸出參數爲output_wordcount

執行完成之後可以看到。

hdfs dfs -ls
Found 2 items
drwxr-xr-x   - haoye supergroup          0 2017-05-06 20:34 input_wordcount
drwxr-xr-x   - haoye supergroup          0 2017-05-06 20:40 output_wordcount
 hdfs dfs -ls output_wordcount
Found 2 items
-rw-r--r--   3 haoye supergroup          0 2017-05-06 20:40 output_wordcount/_SUCCESS
-rw-r--r--   3 haoye supergroup         83 2017-05-06 20:40 output_wordcount/part-r-00000
其中part-r-00000爲結果文件。

我們可以查看它的內容

hdfs dfs -cat output_wordcount/part-r-00000
api	1
file	3
free	2
hadoop	7
hello	3
home	1
java	2
new	2
school	1
system	1
world	2
得到結果了吧。



對於hadoop來說,執行任務需要操作HDFS,需要job對應的jar包。而jar包中需要編寫mapTask和ReduceTask對應的方法。交給jobTracker執行就可以了。十分的方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章