MapReduce--Hadoop学习笔记

FileInputFormat

FileInputFormat是基本的数据读取类型,包括TextInputFormat、KeyValueInputFormat、NLineInputFormat、CombineTextInputFormat以及自定义的InputFormat。

  • TextInputFormat:默认的类型,key是偏移量Long类型,value是一行的数据;
  • KeyValueInputFormat:默认以tab分割,一行数据中tab前是key,tab后面是value;
  • NLineInputFormat:按行数定义切片大小;
  • CombineTextInputFormat:小文件数量较多时会使用,将多个小文件从逻辑上规划到一个切片中。

shuffle机制

Map方法之后,Reduce方法之前的数据处理过程称为Shuffle或洗牌。

partition分区

默认分区是根据key的hashCode对ReduceTasks个数取模得到,用户没法控制哪个key存储到哪个分区。

通过自定义Partitioner,可以实现自定义分区。

例如,按手机号码前三位进行分区。

添加类继承Partitioner,

package partition;

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

/**
 * @author Administrator
 */
public class ProvincePartitioner extends Partitioner<Text, FlowBean> {
    
    
    @Override
    public int getPartition(Text text, FlowBean flowBean, int i) {
    
    
        String prePhoneNum = text.toString().substring(0, 3);

        int partition=4;
        if ("130".equals(prePhoneNum)) {
    
    
            partition = 0;
        } else if ("131".equals(prePhoneNum)) {
    
    
            partition = 1;
        } else if ("132".equals(prePhoneNum)) {
    
    
            partition = 2;
        } else if ("133".equals(prePhoneNum)) {
    
    
            partition = 3;
        }
        return partition;
    }
}

然后在驱动类中添加

job.setPartitionerClass(ProvincePartitioner.class);
job.setNumReduceTasks(5);//默认值是1

这里一共分了5个区,分区号必须从零开始编号、逐一累加。

WritableComparable排序

MapTask和ReduceTask都会对数据按照key进行排序,属于Hadoop的默认行为。

默认排序是按照字典排序,且实现该排序的方法是快速排序。

排序的分类:部分排序、全排序、辅助排序(分组排序)、二次排序。

排序的实现:bean对象作为key传输,实现WritableComparable接口重写compareTo方法。

全排序

全排序要在实例中实现WritableComparable接口重写compareTo方法。

@Override
public int compareTo(FlowBean bean) {
    
    
    int result;

    if (sumFlow>bean.getSumFlow()){
    
    
        result=-1;
    }else if(sumFlow<bean.getSumFlow()){
    
    
        result=1;
    }else {
    
    
        result=0;
    }
    return result;
}

分区排序

即分区和排序的结合。

Combiner合并

Combiner是Reducer的子类,在每一个MapTask所在节点运行。意义在于对每一个MapTask的输出进行局部汇总,以减少网络传输量。不适应于求均值的场景,会影响加权。

辅助排序

再自定义类继承WritableComparator类,重写compare方法,并在启动类关联。

以下为例

package group;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

/**
 * @author Administrator
 */
public class OrderGroupComparator extends WritableComparator {
    
    

    protected OrderGroupComparator(){
    
    
        super(Order.class,true);
    }
    
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
    
    

        Order aBean= (Order) a;
        Order bBean= (Order) b;
        int result;

        if (aBean.getId()>bBean.getId()){
    
    
            result=1;
        }else if (aBean.getId()<bBean.getId()){
    
    
            result=-1;
        }else {
    
    
            result=0;
        }
        return result;
    }
}

OutputFormat

OutputFormat是MapReduce输出的基类,默认值是TextOutputFormat,即把结果记录为文本。

  • TextOutputFormat:文本输出;
  • SequenceFileOutputFormat:输出结果作为后续MapReduce任务的输入;
  • 自定义OutputFormat:包括输出到MySQL、Redis、HDFS等。

压缩与解压

这里以BZip2和Gzip压缩格式为例,直接上代码。

package compress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.CompressionCodecFactory;
import org.apache.hadoop.io.compress.CompressionInputStream;
import org.apache.hadoop.io.compress.CompressionOutputStream;
import org.apache.hadoop.util.ReflectionUtils;

import java.io.*;

/**
 * @author Administrator
 */
public class TestCompress {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    

        //压缩
        //compress("C:/Users/Administrator/Desktop/input/hello.txt","org.apache.hadoop.io.compress.BZip2Codec");
        //compress("C:/Users/Administrator/Desktop/input/hello.txt","org.apache.hadoop.io.compress.GzipCodec");

        //解压
        decompress("C:/Users/Administrator/Desktop/input/hello.txt.gz");
    }

    private static void compress(String fileName, String method) throws IOException, ClassNotFoundException {
    
    

        //获取输入输出流
        FileInputStream fileInputStream = new FileInputStream(new File(fileName));
        Class aClass = Class.forName(method);
        CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(aClass, new Configuration());
        FileOutputStream fileOutputStream = new FileOutputStream(new File(fileName + codec.getDefaultExtension()));
        CompressionOutputStream codecOutputStream = codec.createOutputStream(fileOutputStream);

        //流的拷贝
        IOUtils.copyBytes(fileInputStream,codecOutputStream,1024*1024,false);

        //关闭流
        IOUtils.closeStream(codecOutputStream);
        IOUtils.closeStream(fileOutputStream);
        IOUtils.closeStream(fileInputStream);
    }

    private static void decompress(String fileName) throws IOException {
    
    

        //压缩方式检查
        CompressionCodecFactory factory = new CompressionCodecFactory(new Configuration());
        CompressionCodec codec = factory.getCodec(new Path(fileName));
        if (codec==null){
    
    
            System.out.println("can't process");
            return;
        }

        //获取输入输出流
        FileInputStream fileInputStream = new FileInputStream(new File(fileName));
        CompressionInputStream codecInputStream = codec.createInputStream(fileInputStream);
        FileOutputStream fileOutputStream = new FileOutputStream(new File(fileName + ".decode"));

        //流的对拷
        IOUtils.copyBytes(codecInputStream,fileOutputStream,1024*1024,false);

        //关闭流
        IOUtils.closeStream(fileOutputStream);
        IOUtils.closeStream(codecInputStream);
        IOUtils.closeStream(fileInputStream);

    }
}

猜你喜欢

转载自blog.csdn.net/liuliusix/article/details/109361155