仅使用HDFS的Java-API进行WordCount词频统计工作

文章目录

  • 前言
  • 一、样例输入输出
    • 1.样例输入
    • 2.样例输出
  • 二、程序步骤
    • 1.引入maven依赖
    • 2.配置properties文件
    • 3.实现步骤
  • 三、总结


前言

本文通过仅使用HDFS的原生Java-API,不调用MapReduce,对文本单词进行词频统计。输入和输出文件位置均存放在HDFS上。

本程序使用到了properties配置文件指定连接配置、输入输出地址以及类名等。注意,当把类名写入配置文件并使用时,不能用new,而需要使用Java中的反射来获取类。


一、样例输入输出

1.样例输入

样例输入

2.样例输出

仅使用HDFS的Java-API进行WordCount词频统计工作_第1张图片

二、程序步骤

1.引入maven依赖

首先需要创建一个普通的maven项目,然后引入Hadoop和Junit的maven依赖。Junit主要用于单元测试(本来只有main程序可以运行的,导入Junit之后可以在任意函数前加@Test之后便可直接运行该程序),因此Junit可以根据具体需要和偏好决定是否导入。

maven依赖添加于pom.xml之中,具体配置如下:

<dependencies>
    <dependency>
        <groupId>org.apache.hadoopgroupId>
        <artifactId>hadoop-clientartifactId>
        <version>2.7.2version>
    dependency>
    
    <dependency>
        <groupId>org.apache.hadoopgroupId>
        <artifactId>hadoop-hdfsartifactId>
        <version>2.7.2version>
    dependency>
    
    <dependency>
        <groupId>org.apache.hadoopgroupId>
        <artifactId>hadoop-commonartifactId>
        <version>2.7.2version>
    dependency>

    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.11version>
        <scope>testscope>
    dependency>

    <dependency>
        <groupId>org.junit.jupitergroupId>
        <artifactId>junit-jupiter-apiartifactId>
        <version>RELEASEversion>
    dependency>
    
    <dependency>
         <groupId>junitgroupId>
         <artifactId>junitartifactId>
         <version>4.12version>
         <scope>compilescope>
     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项目地址

第一次写博客,如有不足之处还请大家多多指教、多多包涵。如果觉得我写得不错,也可以点赞或者关注我,我也会定期更新更多的理论及实践的博客。

另,我之前也写过一篇同系列的关于MapReduce的实战文章以及关于Hive的原理介绍文章,也可供大家参考。

附上链接:

利用MapReduce实现账单统计

Hive学习笔记(1)——Hive原理初探

你可能感兴趣的:(Hadoop,hadoop,hdfs,java,大数据)