僅使用HDFS的Java-API進行WordCount詞頻統計工作


前言

本文通過僅使用HDFS的原生Java-API,不調用MapReduce,對文本單詞進行詞頻統計。輸入和輸出文件位置均存放在HDFS上。

本程序使用到了properties配置文件指定連接配置、輸入輸出地址以及類名等。注意,當把類名寫入配置文件並使用時,不能用new,而需要使用Java中的反射來獲取類。


一、樣例輸入輸出

1.樣例輸入

樣例輸入

2.樣例輸出

樣例輸出

二、程序步驟

1.引入maven依賴

首先需要創建一個普通的maven項目,然後引入Hadoop和Junit的maven依賴。Junit主要用於單元測試(本來只有main程序可以運行的,導入Junit之後可以在任意函數前加@Test之後便可直接運行該程序),因此Junit可以根據具體需要和偏好決定是否導入。

maven依賴添加於pom.xml之中,具體配置如下:

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.7.2</version>
    </dependency>
    <!--HDFS-->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.7.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.2</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>RELEASE</version>
    </dependency>
    
    <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
         <scope>compile</scope>
     </dependency>
</dependencies>

2.配置properties文件

ADDRESS=hdfs://centos01:9000
USER=hadoop
INPUT_FILE=/test/HDFS/inputWords.txt
OUTPUT_FILE=/test/HDFS/realOut.txt
CONTEXT_CLASS=wordCount.Context

將該配置文件放在resources目錄下。

3.實現步驟

本項目的大致邏輯和實現步驟是:
1)從properties文件中讀入參數,如用戶名、hdfs連接地址和端口號等,進行連接並獲取FileSystem;

public class myConnection {
   
     

    public static FileSystem fileSystem(Properties properties) throws URISyntaxException, IOException, InterruptedException {
   
     

        URI address=new URI(properties.getProperty(Constants.ADDRESS.getValue()));
        String user=properties.getProperty(Constants.USER.getValue());
        Configuration conf=new Configuration();
        FileSystem System=FileSystem.get(address,conf,user);
        return System;
    }
}

2)新建Context類,用於將原數據存入TreeMap(不使用HashMap的原因是HashMap本身是無序的,想要在輸出時排好順序),該類還包含分割和詞頻統計方法;

public class Context {
   
     
    private TreeMap<String,Integer> map=new TreeMap<String,Integer>();
    public void write(String vocabulary,int num)
    {
   
     
        vocabulary=vocabulary.toLowerCase();
        if(map.containsKey(vocabulary))
            shuffle(vocabulary);
        else
            map.put(vocabulary,num);
    }
    public void write(String vocabulary)
    {
   
     
        if(map.containsKey(vocabulary))
            shuffle(vocabulary);
        else
            map.put(vocabulary,1);
    }
    public void shuffle(String key)
    {
   
     
        map.put(key,map.get(key)+1);
    }
    public TreeMap<String,Integer> read()
    {
   
     
        return map;
    }

}

3)使用Context類,將從HDFS上讀取的源數據進行分割和詞頻統計操作並存入Context.java中的TreeMap中。

public class Reader {
   
     
    public static Context read(Properties properties,FileSystem fileSystem) throws URISyntaxException, IOException, InterruptedException, ClassNotFoundException, IllegalAccessException, InstantiationException {
   
     
        Path path=new Path(properties.getProperty(Constants.INPUT_FILE.getValue()));
        FSDataInputStream in = fileSystem.open(path);
        BufferedReader reader=new BufferedReader(new InputStreamReader(in));
        String line="";
        String contextClassName=properties.getProperty(Constants.CONTEXT_CLASS.getValue());
        Class clazz=Class.forName(contextClassName);
        Context context= (Context) clazz.newInstance();
        while((line=reader.readLine())!=null)
        {
   
     
            //System.out.println(line);
            String[] S=line.split(" ");
            for(String s:S)
            {
   
     
                System.out.println(s);
                context.write(s,1);
            }
        }
        reader.close();
        return context;
    }
}

4)將結果輸出到properties中的指定HDFS路徑。

public static boolean output(Properties properties,FileSystem fileSystem,Context context) throws IOException {
   
     
        TreeMap<String,Integer> myMap=context.read();
        Iterator<Map.Entry<String, Integer>> it=myMap.entrySet().iterator();

        FSDataOutputStream out = null;
        Path outputPath=new Path(properties.getProperty(Constants.OUTPUT_FILE.getValue()));
        if(fileSystem.exists(outputPath))
            fileSystem.delete(outputPath);
        out = fileSystem.create(outputPath);
        while (it.hasNext())
        {
   
     
            java.util.Map.Entry<String,Integer> entry=it.next();
            out.write((entry.getKey()+"\t"+entry.getValue()+"\n").getBytes());
        }
        out.flush();
        out.close();
        fileSystem.close();
        return true;//若成功返回true
    }

二、總結

以上就是本文要講的內容,本文通過僅使用HDFS的原生Java-API,不調用MapReduce,對來自HDFS文本單詞進行詞頻統計操作,並上傳到HDFS上。

最後附上本項目的github地址,供大家參考。github項目地址

第一次寫博客,如有不足之處還請大家多多指教、多多包涵。

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