En primer lugar, la explicación de la demanda

1, la descripción del archivo de datos

Hay algunas hdfs temperatura de almacenamiento de archivos de datos almacenados en forma de texto, por ejemplo:

La fecha y la hora son espacios intermedios, como un todo, un sitio de monitoreo de detección de sincronismo, seguido por la temperatura detectada por la pestaña intermedia t separó.

postbird

2, la demanda

  1. Cálculo 1949--1955 años, la temperatura anual orden descendente y dar salida a los archivos almacenados solo año

La necesidad de particiones personalizadas, agrupando a medida, clasificación personalizado.

En segundo lugar, la solución

1, ideas

  1. Por orden ascendente año y luego de acuerdo con el fin de descender a una temperatura anual
  2. Agrupados por año, cada una correspondiente a un año reducir la tarea

2, el tipo de salida asignador de costumbre par de claves

Como puede verse, cada temperatura fila denominado provisionalmente un conjunto de datos, cada uno de los datos tiene dos partes, una parte del tiempo, el otro es la temperatura.

Por lo tanto Correlación de salida debe personalizar el formato de salida para su uso, así como la necesidad de personalizar la operación después de la salida de ordenar y agrupar similares, los que no son eficaces por defecto.

KEYPAIR definido

Debido a que el tipo de salida de salida que desea personalizar el mapa para entrar en reducir operativa, es necesario para lograr la interfaz hadoop WritableComparable, y las variables de la plantilla de interfaz tiene que ser par de claves, como LongWritable un significado (ver definición en LongWritable puede saber)

WritableComparable implementar interfaces tienen que reescribir los / readFileds / compareTo tres métodos de escritura, sucesivamente a la serialización / deserialización / Comparación

Al mismo tiempo la necesidad de anular los problemas y evitar toString hashCode de igual a igual.

KEYPAIR define como sigue

Se hace notar que: cuando se lleva a cabo una secuencia de salida es decir, escritura, momento en el cual la conversión de formato de hora estándar (formato de archivo de la indicación de tiempo) se realiza por DataInput y DataOutput


import org.apache.hadoop.io.WritableComparable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

/**
 * Project   : hadooptest2
 * Package   : com.mapreducetest.temp
 * User      : Postbird @ http://www.ptbird.cn
 * TIME      : 2017-01-19 21:53
 */

/**
 * 为温度和年份封装成对象
 * year表示年份 而temp为温度
 */
public class KeyPair implements WritableComparable<KeyPair>{
    //年份
    private int year;
    //温度
    private int temp;

    public void setYear(int year) {
        this.year = year;
    }

    public void setTemp(int temp) {
        this.temp = temp;
    }

    public int getYear() {
        return year;
    }

    public int getTemp() {
        return temp;
    }
    @Override
    public int compareTo(KeyPair o) {
        //传过来的对象和当前的year比较 相等为0 不相等为1
        int result=Integer.compare(year,o.getYear());
        if(result != 0){
            //两个year不相等
            return 0;
        }
        //如果年份相等 比较温度
        return Integer.compare(temp,o.getTemp());
    }

    @Override
    //序列化
    public void write(DataOutput dataOutput) throws IOException {
       dataOutput.writeInt(year);
       dataOutput.writeInt(temp);
    }

    @Override
    //反序列化
    public void readFields(DataInput dataInput) throws IOException {
        this.year=dataInput.readInt();
        this.temp=dataInput.readInt();
    }

    @Override
    public String toString() {
        return year+"\t"+temp;
    }

    @Override
    public int hashCode() {
        return new Integer(year+temp).hashCode();
    }
}

3 agrupación personalizada

Será puesto junto con el seguimiento del año la temperatura, por lo que la necesidad de efectuar una comparación año.

Por lo tanto, la comparación de datos de entrada en el año puede prestar atención al tipo de comparación es en esta época del par de claves, un mapa de este tipo de salida también.

Debido heredada WritableComparator, es necesario volver a escribir métodos comparar, la comparación es el par de claves (par de claves se dio cuenta de WritableComparable Interface), su comparación real del año, el mismo año obtuvo 0


/**
 * Project   : hadooptest2
 * Package   : com.mapreducetest.temp
 * User      : Postbird @ http://www.ptbird.cn
 * TIME      : 2017-01-19 22:08
 */

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

/**
 *  为温度分组 比较年份即可
 */
public class GroupTemp extends WritableComparator{

    public GroupTemp() {
        super(KeyPair.class,true);
    }
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        //年份相同返回的是0
        KeyPair o1=(KeyPair)a;
        KeyPair o2=(KeyPair)b;
        return Integer.compare(o1.getYear(),o2.getYear());
    }
}

4, particiones personalizada

El particiones personalizadas objetivo se basa en el año después de un grupo de buenos puntos, diferentes años para crear diferentes reducir tarea tarea, que requiere años de tratamiento.


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

/**
 * Project   : hadooptest2
 * Package   : com.mapreducetest.temp
 * User      : Postbird @ http://www.ptbird.cn
 * TIME      : 2017-01-19 22:17
 */

//自定义分区
//每一个年份生成一个reduce任务
public class FirstPartition extends Partitioner<KeyPair,Text>{
    @Override
    public int getPartition(KeyPair key, Text value, int num) {
        //按照年份进行分区 年份相同,返回的是同一个值
        return (key.getYear()*127)%num;
    }
}

5, la clasificación personalizada

La comparación final es todavía una especie de temperatura, por lo que esta parte es muy importante.

De acuerdo con los requisitos anteriores, la necesidad para el año para la Salud puede clasificar, mientras que la temperatura en orden descendente, con la condición de que el año de comparación preferido .


/**
 * Project   : hadooptest2
 * Package   : com.mapreducetest.temp
 * User      : Postbird @ http://www.ptbird.cn
 * TIME      : 2017-01-19 22:08
 */

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

/**
 *  为温度排序的封装类
 */
public class SortTemp extends WritableComparator{

    public SortTemp() {
        super(KeyPair.class,true);
    }
    //自定义排序
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        //按照年份升序排序 按照温度降序排序
        KeyPair o1=(KeyPair)a;
        KeyPair o2=(KeyPair)b;
        int result=Integer.compare(o1.getYear(),o2.getYear());
        //比较年份 如果年份不相等
        if(result != 0){
            return result;
        }
        //两个年份相等 对温度进行降序排序,注意 - 号
        return -Integer.compare(o1.getTemp(),o2.getTemp());
    }
}

6, programas MapReduce escritura

Varios puntos destacables:

    1. Que precede a la vez que el archivo de datos es una cadena de caracteres, pero nuestro par de claves del conjunto no es una cadena, la cadena se requiere para dar formato a la operación de transferencia de la fecha, utilizando el SimpleDateFormat, naturalmente formato "AAAA-MM-DD HH: MM: ss "el.
    2. Después de introducir los datos para cada fila, a través del juego regular de la pestaña de "t", y después la temperatura y el tiempo se separan y el formato de hora obtenido años, la segunda porción de la cadena de banda símbolo "℃" números obtenidos, y luego crear el tipo de par de claves de datos puede ser de salida.
  1. Cada año genera una tarea de reducir se basa en una partición de encargo del procesamiento de año, en comparación, la salida simplemente poner el mapa con el fin de reducir la salida, una vez más, tres reducir tarea, generará tres archivos de salida.
  2. Debido al uso de la costumbre de clasificación, agrupación, la zonificación, y por lo tanto necesario especificar la clase en cuestión, mientras que el número también a reducir las necesidades de la tarea a realizar.
  3. De hecho, el último cliente o única forma fija ensayo en ocho partes, pero más que la costumbre especificado, nada más.

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
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 org.apache.hadoop.util.GenericOptionsParser;

import java.io.IOException;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * Project   : hadooptest2
 * Package   : com.mapreducetest.temp
 * User      : Postbird @ http://www.ptbird.cn
 * TIME      : 2017-01-19 22:28
 */
public class RunTempJob {
    //字符串转日期format
    public static SimpleDateFormat SDF=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     * Mapper
     * 输出的Key是自定义的KeyPair
     */
    static class TempMapper extends Mapper<LongWritable,Text,KeyPair,Text>{
        protected void map(LongWritable key,Text value,Context context) throws IOException,InterruptedException{
            String line=value.toString();
            //1949-10-01 14:21:02    34℃
            // 前面是空格 时间和温度通过\t分割
            String[] ss=line.split("\t");
//            System.err.println(ss.length);
            if(ss.length==2){
                try{
                    //获得日期
                    Date date=SDF.parse(ss[0]);
                    Calendar c=Calendar.getInstance();
                    c.setTime(date);
                    int year=c.get(1);//得到年份
                    //字符串截取得到温度,去掉℃
                    String temp = ss[1].substring(0,ss[1].indexOf("℃"));
                    //创建输出key 类型为KeyPair
                    KeyPair kp=new KeyPair();
                    kp.setYear(year);
                    kp.setTemp(Integer.parseInt(temp));
                    //输出
                    context.write(kp,value);
                }catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    }
    /**
     *  Reduce 区域
     *  Map的输出是Reduce的输出
     */
    static class TempReducer extends Reducer<KeyPair,Text,KeyPair,Text> {
        @Override
        protected void reduce(KeyPair kp, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            for (Text value:values){
                context.write(kp,value);
            }
        }
    }

    //client
    public static void main(String args[]) throws IOException, InterruptedException{
        //获取配置
        Configuration conf=new Configuration();

        //修改命令行的配置
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.err.println("Usage: temp <in> <out>");
            System.exit(2);
        }
        //创建Job
        Job job=new Job(conf,"temp");
        //1.设置job运行的类
        job.setJarByClass(RunTempJob.class);
        //2.设置map和reduce的类
        job.setMapperClass(RunTempJob.TempMapper.class);
        job.setReducerClass(RunTempJob.TempReducer.class);
        //3.设置map的输出的key和value 的类型
        job.setMapOutputKeyClass(KeyPair.class);
        job.setMapOutputValueClass(Text.class);
        //4.设置输入文件的目录和输出文件的目录
        FileInputFormat.addInputPath(job,new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job,new Path(otherArgs[1]));
        //5.设置Reduce task的数量 每个年份对应一个reduce task
        job.setNumReduceTasks(3);//3个年份
        //5.设置partition sort Group的class
        job.setPartitionerClass(FirstPartition.class);
        job.setSortComparatorClass(SortTemp.class);
        job.setGroupingComparatorClass(GroupTemp.class);
        //6.提交job 等待运行结束并在客户端显示运行信息
        boolean isSuccess= false;
        try {
            isSuccess = job.waitForCompletion(true);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //7.结束程序
        System.exit(isSuccess ?0:1);
    }
}

En tercer lugar, se genera el efecto:

HDFS tres a reducir la tarea genera tres salidas.

postbird

Cada archivo de salida es un ranking anual de la temperatura de los resultados:

postbird

Como puede verse, 1951 es un mapa (se puede decir KEYPAIR) de salida del año, la temperatura es de 46, mientras que la parte posterior es el texto y la salida una vez al año se ordena en orden descendente de acuerdo a la demanda. )