本地windows访问hadoop的hdfs并实现wordcount

一.下载hadoop依赖项

下载地址

https://github.com/cdarlint/winutils

直接下载zip文件,之后保留自己hadoop版本的或者相近版本的就可以,其他都删掉。 

这里我保留的3.3.5 因为我的是3.3.1 

双击 hadoop-3.3.5\bin 下的 winutils.exe,如果闪退,则正常;如果报错,说明缺少微软运行库

 ok下载完成.

二.配置环境变量

配置系统变量:

 

新建一个环境变量,并写入自己的依赖项路径.

 然后再Path中配置:

记得点确定!! 这里可能总共有三个确定,必须全点,否则没用.作者试错过,真的好难崩..希望读者别.. 

三.创建maven项目

files中点击新建项目,选择maven项目,新版idea只有maven archetype 这是maven项目的子项,所以我们点击右上边的Java蓝字。

编辑自己的项目名称和路径,选择自己的jdk,并create。

创建好后打开对应目录下的pom.xml并配置相关依赖项:

添加以下代码:<dependencys>

注意:

版本version要和自己的hadoop相一致!!!比如我的hadoop是3.3.1,不要无脑cp,否则后续可能有bug,junit是java测试项,log4j是日志管理项。

    <dependencies>
        <!--        hadoop相关依赖-->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>3.3.1</version>
        </dependency>

        <!-- 单元测试依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <!-- log4j依赖 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.2</version>
        </dependency>
    </dependencies>

 ok 配置好之后点击最右边的maven,生成依赖项:

生成后会有dependencies 并且内容如下:

依赖项装好之后,添加我们的log4j:在resources中添加log4j.properties文件:

内容如下:这个可以直接无脑cp:

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

也不知道这是什么语言哈哈哈...

ok可以创建我们的包和java文件远程访问啦:我的目录是这样的:

四.远程访问

创建好自己的文件夹就可以访问hdfs,注意要启动我们的hadoop集群别忘记

上传文件:

package ztt.example;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;


public class Java_API {
    /**
     * 测试上传文件
     */
    // 可操作HDFS文件系统的对象
    FileSystem hdfs = null;

    // 测试方法执行前执行,用于初始化操作,避免频繁初始化
    @Before
    public void init() throws IOException {
        // 构造一个配置参数对象,设置一个参数:要访问的HDFS的URI
        Configuration conf = new Configuration();
        // 指定使用HDFS访问
        conf.set("fs.defaultFS","hdfs://hadoop01:8020");
//        conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
        // 进行客户端身份的设置(root为虚拟机的用户名,hadoop集群节点的其中一个都可以)
        System.setProperty("HADOOP_USER_NAME","root");
        // 通过FileSystem的静态get()方法获取HDFS文件系统客户端对象
        hdfs = FileSystem.get(conf);
    }

    // 测试方法执行后执行,用于处理结尾的操作,关闭对象
    @After
    public void close() throws IOException {
        // 关闭文件操作对象
        hdfs.close();
    }

    @Test
    public void testUploadFileToHDFS() throws IOException {
        // 待上传的文件路径(windows)
        Path src = new Path("E:/myStage/the3rd/Big_Data/HDFS-API/test/upload.txt");
        // 上传之后存放的路径(HDFS)
        Path dst = new Path("/wcinput/upload_fr_win.txt");
        // 上传
        hdfs.copyFromLocalFile(src,dst);
        System.out.println("上传成功");
    }
    @Test
    public void testDownFileToLocal() throws IOException {
        // 待下载的路径(HDFS)
        Path src = new Path("/wcinput/word.txt");
        // 下载成功之后存放的路径(windows)
        Path dst = new Path("E:/myStage/the3rd/Big_Data/HDFS-API/test/word.txt");
        // 下载
        hdfs.copyToLocalFile(false,src,dst,true);
        System.out.println("下载成功");
    }

}

 这里如果直接cp ,编译器可能会报错,因为有重名类,读者需要自己重新根据提示选择导入模块的类或包。

结果成功

 内容和hdfs中的一致:

内容就别看啦,这个是我在shell端写的本地文件,上传到hdfs中,现在又被我拉到本地windows下哈哈。 

查看文件所在区块:

如果我想访问一下我的文件在哪个区块,有哪些节点存储了我的文件副本,代码如下:

package ztt.example;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;
import java.util.Arrays;

public class file_loc {
    public static void main(String[] args) {
        String uri = "hdfs://hadoop01:8020/sanguo/shuguo.txt";
        Configuration conf = new Configuration();
        try {
            FileSystem fs = FileSystem.get(new URI(uri),conf,"root");//URI和配置获取HDFS文件系统的实例
            Path path = new Path(uri);
            FileStatus fileStatus = fs.getFileStatus(path);//获取文件状态

            //hdfs文件大小小于一个块的大小,默认128M,所以只有1块block0
            BlockLocation blkLocation[] = fs.getFileBlockLocations(fileStatus,0,fileStatus.getLen());
            System.out.println(Arrays.toString(blkLocation));
            for (int i = 0; i < blkLocation.length; i++) {
                String[] hosts = blkLocation[i].getHosts();//找到主机
//                System.out.println("block_" + i + "_Location:" + hosts[0]);//打印块位置的第一个副本
                System.out.println("block_" + i + "_Location: " + Arrays.toString(hosts));

            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

注意一下,这是放自己的文件路径,不过端口都是8020,具体要看你的hadoop配置文件`core-site.xml` 

结果如下:

五.实现wordcount

首先,在自己项目下新建一个模块吧用于实现自己编写的mapreduce的wordcount:

里面同样有pom.xml的配置项,直接复制粘贴整个项目的就行,这里不多做赘述. (可以看第三点)

还有log4j.properties记得cp过去

创建自己创建模块和定义的三个类:

 各个类的代码如下:

WordCountMapper.java:
package ztt.mapreduce;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/*
* KEYIN:输入类型LongWritable
* KEYOUT:输出key类型Text
* */
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    private Text outK = new Text();
    private IntWritable outV = new IntWritable(1);
    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//        super.map(key, value, context);
        //获取一行
        String line=value.toString();
        //切割
        String[] words=line.split(" ");
        //循环写出
        for(String word:words){
            //封装
            outK.set(word);
            //写出
            context.write(outK, outV);
        }
    }
}
WordCountReducer:
package ztt.mapreduce;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//        super.reduce(key, values, context);

        int sum = 0;
        //apple,(1,1)
        //累加
        for (IntWritable value : values) {
            sum += value.get();
        }
        context.write(key, new IntWritable(sum));
    }

}
JobMain.java:
package ztt.mapreduce;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//        super.reduce(key, values, context);

        int sum = 0;
        //apple,(1,1)
        //累加
        for (IntWritable value : values) {
            sum += value.get();
        }
        context.write(key, new IntWritable(sum));
    }

}

以上代码需要根据情况选择修改,包括输入输出路径等等。

最终run JobMain.java文件即可.

 成功写入:

  • r表示文件来自reduce阶段
  • 00000表示输出文件的编号

文件内容:

 完美啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值