mapreduce

本文详细介绍了MapReduce中的分区功能实现,包括使用partitioner自定义分区逻辑,以及如何按照电话号码前三位进行分区。同时,展示了如何利用TreeSet实现排序功能,包括基本使用和针对自定义Pojo类(如Phone)的排序逻辑编写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.分区功能实现—partitoner分区逻辑书写

1.可以通过设置reduce Task的数量来实现运算结果的拆分

	job.setNumReduceTasks()
	此时,单独进行task数量的设置--->会按照自己的存储规则来进行数据的存储
  • 例如:job.setNumReduceTasks(10);
    可以看到,并不是每个文件都进行了运算结果的存储—>它会按照自己的存储规则进行存储
    在这里插入图片描述

2.如何进行自己分区逻辑的书写?

  • 需要用到 partitoner 分区

     map到reduce进行数据分区,不同分区的数据写进对应的reduce中,进行数据合并
    
  • 原理是 : 我们自己写分区的逻辑,执行代码时,会按照写的逻辑进行分区—>每个区中的数据分配到不同的reduce中执行===>这样不同reduce执行出来的数据就会存放在不同的文件中

  • 以下为代码更新的部分

//        分区逻辑书写
//    key是map KEYOUT的类型,value是map VALUEOUT的类型
    public static class MyPar extends Partitioner<Text, Phone>{

    @Override
    public int getPartition(Text text, Phone phone, int i) {
//        如果phone的前三位等于123-->返回i=0
//        如果phone的前三位等于124-->返回i=1
//        如果phone的前三位等于125-->返回i=2
//        其他情况-->返回i=3
        if (phone.getPhone().substring(0,3).equals("123")){
            i=0;
        }else if (phone.getPhone().substring(0,3).equals("124")){
            i=1;
        }else if (phone.getPhone().substring(0,3).equals("125")){
            i=2;
        }else{
            i=3;
        }
        return i;
    }
}
//            job执行reduce的配置
            job.setNumReduceTasks(4);

//            现在用的是自定义的partitoner--->不用默认的--->所以要进行类上的指定
            job.setPartitionerClass(Demo6.MyPar.class);

在这里插入图片描述

在这里插入图片描述

完整代码

package neuedu.test;

import neuedu.pojo.Phone;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;

import java.io.IOException;

public class Demo6 {
    //    先继承Mapper
    /**
     * 四个范型
     * (1)进行每一行的位置的记录:map读取指定文件中的数据——》每一行开始的位置,数字进行的记录——》我们现在写的是大数据,所以文件会比较大——》可以定义long类型(在大数据里面自己封装的叫做longWritable类型)
     * (2)进行文件中数据的读取:map进行文件中数据的读取(按行读取),一行一行的进行数据获取—-》一行中数据为String类型(在大数据中国自己封装的类型叫做Text类型)
     * (3)进行每一行单词的获取:map进行每一行单词的获取—-》要进行映射(单词,数量1)——》这里还要继续写出给reduce—-》需要key的类型(就是单词类型)—-》也就是字符串类型(大数据中为Text)
     * (4)同(3):map写出到reduce中value的类型(数量1)—-》数字类型(先定义为int)—-》(大数据中为IntWritable)
     * 注意:数量=1–》是因为我们现在写的简单逻辑是一行就看成是一个单词,所以读取一行,就赋值为1
     */
    public static class Map1 extends Mapper<LongWritable, Text,Text, Phone> {
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String[] s=value.toString().split(" ");
            int id=Integer.parseInt(s[0]);
            String phone=(s[1]);
            int up=Integer.parseInt(s[2]);
            int down =Integer.parseInt(s[3]);
            Phone phone1 = new Phone();
            phone1.setId(id);
            phone1.setPhone(phone);
            phone1.setUp(up);
            phone1.setDown(down);
            context.write(new Text(phone),phone1);
        }
    }


//        分区逻辑书写
//    key是map KEYOUT的类型,value是map VALUEOUT的类型
    public static class MyPar extends Partitioner<Text, Phone>{

    @Override
    public int getPartition(Text text, Phone phone, int i) {
//        如果phone的前三位等于123-->返回i=0
//        如果phone的前三位等于124-->返回i=1
//        如果phone的前三位等于125-->返回i=2
//        其他情况-->返回i=3
        if (phone.getPhone().substring(0,3).equals("123")){
            i=0;
        }else if (phone.getPhone().substring(0,3).equals("124")){
            i=1;
        }else if (phone.getPhone().substring(0,3).equals("125")){
            i=2;
        }else{
            i=3;
        }
        return i;
    }
}

//    先继承Reducer
    /**
     * 四个范型
     * (1)map写入reduce中的数据,key类型—》Text
     * (2)map写入reduce中的数据,value类型—》IntWritable
     * (3)单词的类型:reduce进行数据合并,把数据写出到磁盘上,格式是(单词,数量)—》先写出单词的类型(key类型)—》字符串—〉Text
     * (4)数量的类型:value类型—》LongWritable
     */
    public static class Reduce1 extends Reducer<Text,Phone,Phone, NullWritable> {
        /**
         * key===>从map中接受的key的类型
         * values===>是一个集合,进行当前可以相同时,数据值的存储
         * reduce中的数据写出到hdfs上===>通过context进行的写出
         */
        @Override
        protected void reduce(Text key, Iterable<Phone> values, Context context) throws IOException, InterruptedException {
            for (Phone p:values
                 ) {
                int sum=p.getUp()+p.getDown();
                p.setSum(sum);
                context.write(p,null);
            }
        }
    }

    public static void main(String[] args){
//        进行java程序的运行
//        hdfs的配置
        Configuration conf=new Configuration();
        conf.set("fs.defaultFS","hdfs://192.168.246.177:9000");
        try {
            Job job = Job.getInstance(conf);
//            job相关信息
//            设置job的名字
            job.setJobName("javawordcount");
//            job运行类
            job.setJarByClass(Demo6.class);

//            job执行map相关信息的配置
            job.setMapperClass(Demo6.Map1.class);
//                向reduce输出key的类型
            job.setMapOutputKeyClass(Text.class);
//                向rudece输出value的类型
            job.setMapOutputValueClass(Phone.class);

//            job执行reduce的配置
            job.setReducerClass(Demo6.Reduce1.class);
            job.setOutputKeyClass(Phone.class);
            job.setOutputValueClass(NullWritable.class);
            job.setNumReduceTasks(4);

//            现在用的是自定义的partitoner--->不用默认的--->所以要进行类上的指定
            job.setPartitionerClass(Demo6.MyPar.class);

//            注意导包import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
            FileInputFormat.setInputPaths(job,new Path("/phone.txt"));
            FileOutputFormat.setOutputPath(job,new Path("/java04"));

//            提交执行
            job.waitForCompletion(true);

        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

二.排序功能实现

1.TreeSet引入

  • (1)简单的TreeSet
package neuedu.test;

import java.util.TreeSet;

public class test3 {
    public static void main(String[] args){
        TreeSet<String> sets=new TreeSet<>();
        sets.add("fes");
        sets.add("aef");
        sets.add("ssg");
        sets.add("fseg");
        System.out.println(sets);//输出结果:[aef, fes, fseg, ssg]

        TreeSet<Integer> set=new TreeSet<>();
        set.add(1);
        set.add(463);
        set.add(43);
        set.add(12);
        set.add(654);
        System.out.println(set);//输出结果:[1, 12, 43, 463, 654]
    }
}

  • (2)如果创建一个pojo对象,可不可以进行排序呢?
  • pojo类–>Stu
package neuedu.pojo;

import lombok.Data;

@Data
public class Stu {
    private String name;

    public Stu(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private int age;
}

  • 测试
        TreeSet<Stu> stus = new TreeSet<>();
        stus.add(new Stu("张三",12));
        stus.add(new Stu("李四",34));
        stus.add(new Stu("王五",00));
        stus.add(new Stu("赵六",45));
        stus.add(new Stu("宋七",11));
        System.out.println(stus);
    }
	测试之后会发现报错:Exception in thread "main" java.lang.ClassCastException: neuedu.pojo.Stu cannot be cast to java.lang.Comparable
	因为用TreeSet进行排序需要继承comparable,书写compareTo逻辑
	String和int可以使用TreeSet是因为String类和int类中有compareTo逻辑
	而我们自己创建的pojo类还没有compareTo逻辑--->所以会报错,不能排序
  • 在Stu中添加CompareTo
package neuedu.pojo;

import lombok.Data;

@Data
public class Stu implements Comparable<Stu>{
    private String name;

    public Stu(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private int age;

    @Override
    public int compareTo(Stu o) {
        return this.age-o.age;//按照年龄的升序排序
//        return -(this.age-o.age);//按照年龄的降序排序
    }
}

这时测试,输出结果为[Stu(name=王五, age=0), Stu(name=宋七, age=11), Stu(name=张三, age=12), Stu(name=李四, age=34), Stu(name=赵六, age=45)]

2.对phone.txt文件进行排序实现

(1)写compareTo逻辑

  • WritableComparable 既能序列化,也能作数据的比较
    在这里插入图片描述
  • pojo类–Phone.java
package neuedu.pojo;

import lombok.Data;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;

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

@Data
//public class Phone implements Writable,Comparable<Phone> {
public class Phone implements WritableComparable<Phone> {

    private int id;
    private String phone;
    private int up;
    private int down;
    private int sum;
    private int status;

    @Override
    public String toString() {
        return phone+'\t'+up+'\t'+down+'\t'+sum;
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeInt(this.id);
        dataOutput.writeUTF(this.phone);
        dataOutput.writeInt(this.up);
        dataOutput.writeInt(this.down);
        dataOutput.writeInt(this.status);
        dataOutput.writeInt(this.sum);
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.id=dataInput.readInt();
        this.phone=dataInput.readUTF();
        this.up=dataInput.readInt();
        this.down=dataInput.readInt();
        this.status=dataInput.readInt();
        this.sum=dataInput.readInt();
    }

    @Override
    public int compareTo(Phone o) {
        return this.up-o.up;
    }
}

23:22视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值