仅使用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项目地址

第一次写博客,如有不足之处还请大家多多指教、多多包涵。

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