MapReduce以及第一个案例wordcount

MapReduce
处理海量数据怎么计算的问题
Mapreduce是一种思想,也是一种计算框架
MapReduce给我们的规范:(框架)
1.思想的规范:
map:映射 key-value
把数据划分为最小的数据单元。
什么是最小 》按照实际的业务逻辑划分最小单位。
reduce:合并
按key相同的,value值合并。
合并的两种方案:1.每一组分别合并
2.整体进行合并。
2.代码的规范
Mapper类
把数据划分为最小的数据单元。,以键值对展示的具体代码实现
Reducer
按Key相同,value值合并。以键值对展示的具体代码实现
Driver
一般是主方法,指定一些Mapper和Reducer的一些特有的一些情况。
比如输出输入文件 输入输出泛型 等。
wordCount 案例:
思路:
1.必须有原文件(很多行数据,每一行都有很多单词用空格分开)
2.每一行都会执行一次map操作
(对每一行数据都进行split分割,形成单词的数组)
注意:所有行执行完操作之后才能执行reduce操作
3.把分割出来的数组循环,在循环体内把每个单词以键值对(key,1)向下传递
4.reduce接收的数据样式是(key,1,1,1,2)
5.对序列里的数据求和。
6.把结果写出到文件中。
代码:

     package mapReduce.wordCount;

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;
/*
Mapper<LongWritable,Text,Text,IntWritable>
注意:所有的泛型一定是可以序列化的(与java的序列化原理一样,表现形式不同)
文件作为mapper的输入,最小的数据单元以键值对的形式作为输出。
LongWritable:文件的偏移量
       偏移量是指能控制文件中每一行数据开头的数字,如第一行有10个字符,那么第二行
       的开头就是11.
Text:文件每行的实际内容。
Text:输出时候的实际内容(这里指的是单词)
IntWritable:每个单词对应的数字。
 */

/*
Mapper中的方法:
 setup:任务开始时,最先开始执行的程序,仅执行一次,相当于初始化一些内容,一般不会重写
 map;每来一个键值对,都需要执行一次map方法,划分最小数据单元的操作就在这里执行。一般需要重写。
 cleanUp:任务结束时,最后执行的程序,仅执行一次,相当于做一些收尾的工作,一般不重写
 run:涉及一些核心内容,没有涉及特殊情况不重写
 就像经典的理论:打开冰箱,将每一头猪依次放进去。最后关上冰箱。
 */
public class WordCount extends Mapper<LongWritable,Text,Text,IntWritable>{
    Text outkey = new Text();
    IntWritable outvalue = new IntWritable();
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //把从文件读出的每行内容变成String类型
        String line = value.toString();
        //把每行内容划分成每一个独立的单词
        String[] words = line.split(" ");
        //循环遍历数组,把数组中的每个单词以(key,1)的形式输出到reduce。
        for(String word : words){
           // context.write(new Text(word),new IntWritable(1));//第一种方式
            outkey.set(word);//第二种方式
            outvalue.set(1);
            context.write(outkey,outvalue);
        }

    }
}
package mapReduce.wordCount;

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, Context context) throws IOException, InterruptedException {
        //求和的初始值。
        int sum = 0;
        //每一个单词,把带进来的序列化数字求和
        for(IntWritable value:values){
            sum+=value.get();
        }
        //把最终文件写入。
        context.write(key,new IntWritable(sum));
    }
}
package mapReduce.wordCount;


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.FileInputStream;
import java.io.IOException;


public class WordCountDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //创建一个job的实例
        Job job = Job.getInstance();

        //4设置4个输出泛型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //3设置3个类()
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCount.class);
        job.setReducerClass(WordCountReducer.class);
        //2设置两个路径(输入和输出)
        FileInputFormat.setInputPaths(job,new Path("file:///C:/WordCount/int.txt"));
        FileOutputFormat.setOutputPath(job,new Path("file:///C:/WordCount/out.txt"));
        //1 提交任务
        job.waitForCompletion(true);
    }
}

代码中的问题:
1.输入输出路径:
可以像上面代码WordCountDriver中一样,将路径写死,但是当我们打jar包放在linux中执行的时候,不方便,所以,可以采用参数的方式写路径,打开run–》Edit Configurations—》Program arguments,在其中写路径,注意:路径之间用空格隔开
在这里插入图片描述
在这里插入图片描述
改了之后输入输出路径的代码:

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

2.通过路径手动删除的问题
如果上面代码中的输出路径存在,那么,用代码直接删除。

 /判断路径是否存在,如果存在,就删除。
        //创建一个输出路径
        Path outputpath = new Path(args[1]);
        //通过输出路径创建一个文件系统的流
        FileSystem fs = FileSystem.get(new URI(outputpath.toString()),new Configuration());
        //判断当前文件系统是否存在这个输出路径
        if(fs.exists(outputpath)){
            //如果存在,就删除。
            fs.delete(outputpath,true);
        }

3.控制台信息的显示问题:
在resource下放log4j.properties文件。
4.对driverClass的改写,并且采用内部类的形式改写代码:

package mapReduce.wordCount;

import mapReduce.wordCount.common.SubmitJobUtil;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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 javax.security.auth.login.Configuration;
import java.io.IOException;
import java.net.URI;

public class WordCountApp {
    public static class wcMapper extends Mapper<LongWritable,Text,Text,IntWritable>{
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] words =line.split(" ");
            for(String word : words){
                context.write(new Text(word),new IntWritable(1));
            }
        }
    }
    public static class wcReducer extends Reducer<Text,IntWritable,Text,IntWritable>{
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum=0;
            for(IntWritable value: values){
                sum += value.get();
            }
            context.write(key,new IntWritable(sum));
        }
    }

    public static void main(String[] args) throws Exception {
//        Job job = Job.getInstance();
//
//        job.setMapOutputKeyClass(Text.class);
//        job.setMapOutputValueClass(IntWritable.class);
//        job.setOutputKeyClass(Text.class);
//        job.setOutputValueClass(IntWritable.class);
//
//        job.setJarByClass(WordCountApp.class);
//        job.setMapperClass(wcMapper.class);
//        job.setReducerClass(wcReducer.class);
//
//        Path outpath = new Path(args[1]);
//        FileSystem fs = FileSystem.get(new URI(outpath.toString()),new org.apache.hadoop.conf.Configuration());
//        if(fs.exists(outpath)){
//            fs.delete(outpath,true);
//        }
//
//        FileInputFormat.setInputPaths(job,new Path(args[0]));
//        FileOutputFormat.setOutputPath(job,new Path(args[1]));
//
//        job.waitForCompletion(true);
        SubmitJobUtil.submitJob(WordCountApp.class,args);
    }
}

package mapReduce.wordCount.common;

import mapReduce.wordCount.WordCountApp;
import org.apache.hadoop.fs.FileSystem;
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.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.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;

public class SubmitJobUtil {

    public static void submitJob(Class driverClass, String[] args) throws Exception {
        Job job = Job.getInstance();

      Class[] innerClasses = driverClass.getClasses();
        job.setJarByClass(driverClass);
        for(Class innerClass:innerClasses){
            //获取当前内部类父类的所有泛型
            ParameterizedType paraType = (ParameterizedType)innerClass.getGenericSuperclass();
            //把获得的所有泛型参数化,变成数组的形式方便使用
            Type[] types = paraType.getActualTypeArguments();
            //获得Mapper或者reducer类的输出key的类型。
            Type outKeyType = types[2];
            //获得Mapper或者reducer类的输出value的类型
            Type outValueType = types[3];
            //判断当前的内部类中哪一个类是mapper,哪一个是reducer。
            if (Mapper.class.isAssignableFrom(innerClass)){
                job.setMapperClass(innerClass);
                job.setMapOutputKeyClass(Class.forName (outKeyType.getTypeName()));
                job.setMapOutputValueClass(Class.forName (outValueType.getTypeName ()));
            }else if(Reducer.class.isAssignableFrom(innerClass)){
                job.setReducerClass(innerClass);
                job.setOutputKeyClass(Class.forName (outKeyType.getTypeName()));
                job.setOutputValueClass(Class.forName (outValueType.getTypeName ()));
            }
        }

        Path outpath = new Path(args[1]);
        FileSystem fs = FileSystem.get(new URI(outpath.toString()),new org.apache.hadoop.conf.Configuration());
        if(fs.exists(outpath)){
            fs.delete(outpath,true);
        }

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

        job.waitForCompletion(true);

    }
}

如果在 job.setMapOutputKeyClass(Class.forName (outKeyType.getTypeName()));中显示没有getTypeName()这个方法,请把jdk改成1.8版本试试。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值