【云计算导论实验3】MapReduce编程

前置环境

需要搭建好hadoop伪分布式集群平台,未搭建好的可以看这个教程 万字详解,Hadoop大数据技术简介及 伪分布式集群搭建快速入门教程

Eclipse环境配置

Eclipse(Windows 本地系统的)

1. 安装插件:

hadoop-eclipse-plugin-2.7.3.jar

地址:https://pan.baidu.com/s/1BaAOQkZaY4RvUPuBPVlgJg 提取码:067u

将插件复制到eclipse目录下的dropins目录
1

2. 配置MapReduce环境:

配置好Hadoop插件后,接下来配置开发环境,连接到Hadoop集群,相关步骤如下:
(1) 增加Map/Reduce功能区
1

2

(2) 增加Hadoop集群的连接

1

点蓝色小象新建一个Locations

2
这里需要填的有:
相关的连接配置信息有:

①Location name:命名新建的Hadoop连接,随便写

②Map/Reduce(V2)Master:填写Hadoop集群的ResourceManager的IP和端口,从以前配置Hadoop集群的yarn-site.xml找

③DFS Master:填写Hadoop集群的NameNode的IP和端口,从以前配置的core-site.xml找
1
2
如果没有配置相关端口,那么就用默认的设置即可,最后finish配置完成。

这里有一个坑,点击已创建的Locations可能会报错,如果设置没问题的话,不用管他

3

(3) 浏览HDFS上的目录及文件

配置完成Hadoop集群的连接信息后,就可以在Eclipse界面浏览HDFS上的目录和文件了,还可以通过鼠标来进行文件操作
在这里插入图片描述

需要注意的是,执行操作后,需要刷新HDFS列表,从而获得文件目录的最新状态。

3. 新建MapReduce工程

本部分将在Eclipse建立MapReduce工程MemberCount,大体按照下面四个步骤进行:

(1)导入MapReduce运行依赖的jar包

首先将虚拟环境中的hadoop包导入到本地环境下,导入过程如下:
1
2
这里需要在本地windows系统下解压一个hadoop,并将路径设置上去。

(2)创建MapReduce工程

在这里插入图片描述
在这里插入图片描述
(3)在MapReduce Project的界面创建工程

在这里插入图片描述
(4)查验是否创建好工程

在这里插入图片描述

设置 log4j.properties

需要在工程的src目录下新建一个log4j.properties文件,其内容如下

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

其他杂七杂八的坑点及环境设置

1. 计算机用户名不能出现空格

cmd中使用下述命令查看用户名

whoami

在这里插入图片描述
修改方法如下:
右键开始按钮,选择【计算机管理】,如下图所示进行修改,修改后需重启后生效,但是不急着重启,因为后边还有。
在这里插入图片描述

2. hadoop.dll 缺失

在这个链接中https://github.com/4ttty/winutils找到相应版本的hadoop.dll下载

然后将其放到C:\Windows\System32目录下

在这里插入图片描述

3. Windows下还需要winutils.exe文件

https://github.com/4ttty/winutils找到相应版本的winutils.exe下载

然后将其放到本地hadoop目录下的bin文件夹里,然后进行环境变量的设置

新建如下系统变量HADOOP_HOME,值为hadoop的安装目录
在这里插入图片描述
然后设置Path变量,添加一项内容为

%HADOOP_HOME%\bin

在这里插入图片描述
重启后生效

4. 修改dfs.permissions为false

切换到下图路径下
在这里插入图片描述
使用命令vim hdfs-site.xml新增下面的property,若已存在将其value修改为false

<property>
	<name>dfs.permissions</name>
	<value>false</value>
</property>

MapReduce程序案例——词频统计程序

目录结构

在这里插入图片描述

代码

WordCountMapper类,继承于Hadoop的Mapper:

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;
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // key 偏移量    value 每行文本:I love Guiyang
        // 按照空格对每行文本进行分词操作:[I,love,Guiyang]
        String line = value.toString(); // 数据类型的转换
        String[] words = line.split(" "); // 对字符串进行拆分 [I,love,Guiyang]
        for (int i = 0; i < words.length; i++) {
            // (I,1)
            Text word = new Text(words[i]);
            IntWritable value2 = new IntWritable(1);
            context.write(word,value2);
        }
    }
}

WordCountReducer类,继承于Hadoop的Reducer:

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 k3, Iterable<IntWritable> v3, Context context) throws IOException, InterruptedException {
        // 进行求和操作,需要计算v3的长度
        // <I,[1,1]>
        int count = 0;
        for (IntWritable v: v3) {
            int value = v.get();
            count += value;
        }
        context.write(k3,new IntWritable(count));
    }
}

WordCountJob类

import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordCountJob {    
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {       // 实列化Job       
	 Job job = Job.getInstance();       
	 job.setJarByClass(WordCountJob.class);        // 设置Mapper      
	 job.setMapperClass(WordCountMapper.class);       
	 job.setMapOutputKeyClass(Text.class);        
	 job.setMapOutputValueClass(IntWritable.class);        // 设置Reducer        
 	job.setReducerClass(WordCountReducer.class);       
	 job.setOutputKeyClass(Text.class);        
	job.setOutputValueClass(IntWritable.class);        // 指明输入文件的路径        
	FileInputFormat.setInputPaths(job,new Path("hdfs://192.168.80.128:8020/input/One Hundred Years of Solitude.txt"));        // 指明输出文件的路径        
	FileOutputFormat.setOutputPath(job,new Path("d:/mr_result/wc01"));        // 开始运行任务        
	boolean completion = job.waitForCompletion(true);       
	 if (completion){          
 	 System.out.println("程序运行成功~");       
	 }
	else {            System.out.println("程序运行失败~");        }   
 }
}

在本地执行

创建输入文件wordcount.txt,其内容为:

I love Guiyang I love Guizhou Guiyang is the capical of Guizhou

WordCountJob类中的第16行设置好本地输入文件路径

FileInputFormat.setInputPaths(job,new Path("d:/wordcount.txt")); 

在这里插入图片描述
WordCountJob类中右键,选择【Run As】-【1 Java Application】

若报错如下图所示,说明输出路径已存在,删掉就可以了
在这里插入图片描述
成功运行则如下图所示

1
结果如下:
在这里插入图片描述
在这里插入图片描述

在Hadoop伪分布式集群上执行

需先启动相应服务,命令为:

start-all.sh

在DFS Locations相应路径上右键,点击【Upload files to DFS】

将测试文件One Hundred Years of Solitude.txt上传至HDFS文件服务器上

需要完成的任务是统计词频并找出词频最高的前100个词及其出现次数

分为两步:统计词频按词频排序

统计词频

与之前的程序相差不大,仅在WordCountMapper类中增加了对符号的处理,新的WordCountMapper类代码如下:

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;
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // key 偏移量    value 每行文本:I love Guiyang
        // 按照空格对每行文本进行分词操作:[I,love,Guiyang]
        String line = value.toString(); // 数据类型的转换
        line = line.replaceAll("--------------------------------------------------------------------------------", "");
        line = line.replaceAll("[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~0-9]", "");//去除符号和数字
        String[] words = line.split(" "); // 对字符串进行拆分 [I,love,Guiyang]
        
        for (int i = 0; i < words.length; i++) {
            // (I,1)
            Text word = new Text(words[i]);
            IntWritable value2 = new IntWritable(1);
            context.write(word,value2);
        }
    }
}

WordCountJob类中的第16行设置好云输入文件路径

FileInputFormat.setInputPaths(job,new Path("hdfs://192.168.80.128:8020/input/One Hundred Years of Solitude.txt"));        // 指明输出文件的路径        
 

在这里插入图片描述
WordCountJob类中右键,选择【Run As】-【2 Run on Hadoop】

成功运行则如下图所示

1
结果如下:
在这里插入图片描述
在这里插入图片描述

按词频排序

将词频统计结果保存到res1文件中并上传至HDFS服务器中作为排序的输入文件。
新建一个按词频排序程序的工程,结构如下:
1

按词频排序代码如下:

tongji类,自定义的数据类型:

import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;


public class tongji implements WritableComparable <tongji>{
    private long number;

    public tongji(long number) {
        this.number = number;
    }

    public tongji() {
    }

    public long getNumber() {
        return number;
    }

    public void setNumber(long number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return String.valueOf(number);
    }

    @Override
    public int compareTo(tongji o) {
        int result;

        // 按照总流量大小,倒序排列
        if (number > o.getNumber()) {
            result = -1;
        }else if (number < o.getNumber()) {
            result = 1;
        }else {
            result = 0;
        }

        return result;
    }


    @Override
    public void write(DataOutput out) throws IOException {
        out.writeLong(number);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        number =in.readLong();
    }
}

WordCountMapper类,继承于Hadoop的Mapper:

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

import java.io.IOException;

public class WordcountMapper extends Mapper<LongWritable, Text, tongji, Text>{

    tongji k = new tongji();
    Text v = new Text();
    @Override
    protected void map(LongWritable key, Text value,Context context)
            throws IOException, InterruptedException {
        //获取一行
        String line = value.toString();
        //切割单词
        String[] fields = line.split("\t");
        // 3 封装对象
        String danci = fields[0];
        long number = Long.parseLong(fields[1]);
        k.setNumber(number);
        v.set(danci);
        context.write(k,v);
    }
}

WordCountReducer类,继承于Hadoop的Reducer:

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

import java.io.IOException;

public class WordCountReducer extends Reducer<tongji,Text,Text, tongji> {

    @Override
    protected void reduce(tongji key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {
        for (Text value : values) {
            context.write(value,key);
        }

    }
}

WordcountDriver类

import java.io.IOException;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordcountDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //获取job
        Job job = Job.getInstance();
        //设置jar包
        job.setJarByClass(WordcountDriver.class);
        //关联mapper和reducer
        job.setMapperClass(WordcountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        //map输出的k和v
        job.setMapOutputKeyClass(tongji.class);
        job.setMapOutputValueClass(Text.class);
        //最终输出kv
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(tongji.class);
        // 指明输入文件的路径        
    	FileInputFormat.setInputPaths(job,new Path("hdfs://192.168.80.128:8020/input/res1.txt"));        
    	// 指明输出文件的路径        
    	FileOutputFormat.setOutputPath(job,new Path("hdfs://192.168.80.128:8020/output/mr_result/wc02"));     
        //提交job
    	// 开始运行任务        
    	boolean completion = job.waitForCompletion(true);       
    	 if (completion){          
     	 System.out.println("程序运行成功~");       
    	 }
    	else {            System.out.println("程序运行失败~");        }   
    }
}

执行结果如下:
1

查看 集群所有应用程序 的信息

在:8088中可以看到程序在hadoop上运行的记录

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒商

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值