大数据平台实验三:MapReduce操作实践;讨厌的数组溢出是什么鬼?

1.MapReduce基本知识的总结

MapReduc的相关知识可以简单分为以下几点:

1.1拆解数据(即Map):

将大规模数据分割成小块。

每个小块都有自己的任务。

这些任务是简单的处理,比如筛选、排序或计数。

1.2处理过程:

各个小块同时进行处理,互不干扰。

并行处理使得整体速度更快。

每个小块处理完后生成中间结果。

1.3组合结果(Reduce):

将各个小块的中间结果收集起来。

将这些结果按照某种方式组合起来。

最终得到一个完整的处理结果。

2.MapReduce的操作实践

2.1基于MapReduce的WordCount实践

0.首先,本文默认环境为Linux的Ubuntu操作环境且已经安装、配置好了hadooop、Maven、idea、jdk等前置配置。

1.编写对应代码,复制导入core-site.xmlhdfs-site.xml两文件(在安装的etc/hadoop路径下):

2.pom文件的配置:

如果你的idea,Maven配置是正常的那么在创建项目时构建系统选择Maven后文件夹会自动生成pom文件,但其中配置需要自己调整:

pom代码实现:
(注意,版本号是hadoop对应版本号,我的是2.10.0)
<?xml version="1.0" encoding="UTF-8"?>
<!-- Maven项目描述文件 -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- 模型版本 -->
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目组织标识 -->
    <groupId>org.example</groupId>
    <!-- 项目唯一标识 -->
    <artifactId>Main</artifactId>
    <!-- 项目版本 -->
    <version>1.0-SNAPSHOT</version>

    <!-- 依赖项 -->
    <dependencies>
        <!-- Hadoop通用模块 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.10.0</version>
        </dependency>
        <!-- Hadoop分布式文件系统模块 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.10.0</version>
        </dependency>
        <!-- Hadoop MapReduce核心模块 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.10.0</version>
        </dependency>
        <!-- Hadoop MapReduce作业客户端模块 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
            <version>2.10.0</version>
        </dependency>
        <!-- Hadoop MapReduce通用模块 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-common</artifactId>
            <version>2.10.0</version>
        </dependency>
    </dependencies>
</project>

3.*Program arguments配置:

(某菜鸟因为没整这个卡了半小时)

如果你卡在一个莫名其妙的数组溢出的bug处(arg[]数组溢出),那么这就是溢出的原因:

打开中文的编辑配置

出现自己文件名的配置处

配置蓝框内内容

注意:对应的inputoutput需要自己提前创建,我创建在/user/ws/input output下,所以在hdfs://localhost:9000/user/ws/input

然后就可以开始创建了,不过在点击构建前,请把那个该死的HDFS使用start-dfs.sh代码打开

创建成功会返回0哦:

输入cat查看单词计数成果:

代码实现
package com.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.StringTokenizer;

public class WordCount {

    public static class MyMapper extends Mapper<Object, Text, Text, IntWritable> {
        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            StringTokenizer itr = new StringTokenizer(value.toString());
            while (itr.hasMoreTokens()) {
                word.set(itr.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();

        public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable val : values) {
                sum += val.get();
            }
            result.set(sum);
            context.write(key, result);
        }
    }

    
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "word count");

        job.setJarByClass(WordCount.class);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        // 检查输入路径是否存在
        Path inputPath = new Path(args[0]);
        FileSystem fs = inputPath.getFileSystem(conf);
        if (!fs.exists(inputPath)) {
            System.err.println("Input path does not exist: " + args[0]);
            System.exit(1);
        }

        FileInputFormat.addInputPath(job, inputPath);
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        // 删除输出目录
        Path outputPath = new Path(args[1]);
        fs.delete(outputPath, true);

        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }

}


2.2 自定义Hadoop数据类型实践

如上图,修改主要如下:

Mapper类的实现:

在修改后版本中,Mapper类中的map方法将每个单词作为键,其长度作为值写入上下文。

在原版本中,Mapper类中的map方法将每个单词作为键,将固定值1作为值写入上下文。这种方法通常用于计数操作,即将每个单词视为一个计数单位。

Reducer类的实现:

在两个版本中,Reducer类都计算了单词出现的总次数,并将结果写入输出上下文。

在修改后版本中的Reducer还计算了单词的平均长度,并将其作为整数写入输出上下文中。

在原版本中Reducer只计算了单词出现的总次数,并将其作为整数写入输出上下文中。

main方法的实现:

在修改后版本中的main方法中,设置了输出值类型为Text,并且在输出结果时采用了Text类型。

在原版本的main方法中,设置了输出值类型为IntWritable,与Reducer中的输出值类型匹配。

其余配置(core-site.xml与hdfs-site.xml以及pom文件如2.1所示)

代码实现
package com.hadoop;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.StringTokenizer;

public class WordCount {


    public static class MyMapper extends Mapper<Object, Text, Text, IntWritable> {
        private Text word = new Text();
        private IntWritable length = new IntWritable();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            StringTokenizer itr = new StringTokenizer(value.toString());
            while (itr.hasMoreTokens()) {
                String token = itr.nextToken();
                word.set(token);
                length.set(token.length());
                context.write(word, length); // 将单词和其长度作为输出
            }
        }
    }
    public static class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();

        public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            int count = 0;
            for (IntWritable val : values) {
                sum += val.get();
                count++;
            }
            int averageLength = sum / count; // 将平均长度转换为整数
            result.set(averageLength);
            context.write(key, result);
        }
    }
    

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "word count");

        job.setJarByClass(WordCount.class);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);

        job.setOutputKeyClass(Text.class);
        //job.setOutputValueClass(Text.class); // 输出值类型改为 Text
        job.setOutputValueClass(IntWritable.class);
        // 检查输入路径是否存在
        Path inputPath = new Path(args[0]);
        FileSystem fs = inputPath.getFileSystem(conf);
        if (!fs.exists(inputPath)) {
            System.err.println("Input path does not exist: " + args[0]);
            System.exit(1);
        }

        FileInputFormat.addInputPath(job, inputPath);
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        // 删除输出目录
        Path outputPath = new Path(args[1]);
        fs.delete(outputPath, true);

        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }

}


2.3 多mapReduce任务的串联实践

(免责声明:这里本菜鸟有点不会,不能确保是对的哦,如果这里或者上面有什么问题,欢迎佬指出)

注意:环境配置如2.1所示。

实现方法:

Mapper阶段: Mapper将每个单词作为键,并将固定值1作为值写入上下文。

Combiner阶段(可选): Combiner是一个在Mapper和Reducer之间执行的本地聚合操作,它可以减少数据传输量。在这种情况下,Combiner可以简单地对相同的单词进行局部聚合,以减少网络传输。但在这个任务中,Combiner是可选的,因为单词的数量不影响最终结果。

Reducer阶段: Reducer对相同的单词进行聚合,并计算出单词出现总次数,而不是单词出现的次数。

设置Job: 设置MapReduce作业,并指定Mapper、Reducer和Combiner。

运行Job: 运行MapReduce作业,并查看输出结果,即所有单词的总数。

成果如下:

代码实现:
package com.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.StringTokenizer;

public class WordCount {

    public static class MyMapper extends Mapper<Object, Text, Text, IntWritable> {
        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            StringTokenizer itr = new StringTokenizer(value.toString());
            while (itr.hasMoreTokens()) {
                word.set(itr.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();

        public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable val : values) {
                sum += val.get();
            }
            result.set(sum);
            context.write(new Text("Total Words"), result); // 输出总单词数
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "word count");

        job.setJarByClass(WordCount.class);
        job.setMapperClass(MyMapper.class);
        job.setCombinerClass(MyReducer.class); // 可选,使用Reducer作为Combiner
        job.setReducerClass(MyReducer.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        FileSystem fs = FileSystem.get(conf);
        fs.delete(new Path(args[1]), true);

        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值