Hadoop의 맵리듀스 직렬화

bbf48a5f21c2b1999ba1bd00b528c9e6.jpeg

 

목차

 

직렬화란 무엇입니까?

역직렬화란 무엇입니까?

직렬화하는 이유:

Java의 직렬화:

Hadoop 직렬화:

사용자 지정 직렬화 인터페이스:

직렬화를 달성하기 위한 단계:

먼저 간단한 분석을 위해 소스 코드를 살펴보십시오.

직렬화 사례 사례:

케이스 요구 사항:

(1) 입력 데이터:

(2) 입력 데이터 형식:

(3) 예상 출력 데이터 형식

수요 분석:

MapperReduce 프로그램을 작성하십시오.   


 

직렬화란 무엇입니까?

        직렬화는 디스크 저장(지속성) 및 네트워크 전송을 위해 메모리의 개체를 바이트 시퀀스(또는 기타 데이터 전송 프로토콜)로 변환하는 것입니다.

역직렬화란 무엇입니까?

        역직렬화는 수신된 바이트 시퀀스(또는 기타 데이터 전송 프로토콜) 또는 디스크의 영구 데이터를 메모리의 개체로 변환하는 것입니다.

직렬화하는 이유:

        일반적으로 "라이브" 개체는 메모리에만 존재하며 전원이 꺼지면 사라집니다. 그리고 "라이브" 개체는 로컬 프로세스에서만 사용할 수 있으며 네트워크의 다른 컴퓨터로 보낼 수 없습니다. 그러나 직렬화는 "라이브" 개체를 저장할 수 있으며 "라이브" 개체를 원격 컴퓨터로 보낼 수 있습니다.

Java의 직렬화:

        Java에도 직렬화가 있는데 아이디어를 통해 Java 직렬화를 사용하지 않는 이유는 무엇입니까?

Java의 직렬화 프레임워크(Serializable)는 수반되는 정보(다양한 검증 정보, 헤더, 상속 시스템 등)가 많은 무거운 프레임워크이기 때문에 네트워크에서 효율적인 전송이 편리하지 않습니다. 따라서 Hadoop은 자체적으로 직렬화 메커니즘(Writable)을 개발했습니다.

Hadoop 직렬화:

        Hadoop의 직렬화는 간단한 검증, 컴팩트(저장 공간의 효율적인 사용), 빠르고(데이터 읽기 및 쓰기에 대한 낮은 오버헤드), 상호 운용성(다국어 상호 작용 지원)으로 비교적 능률적입니다.

사용자 지정 직렬화 인터페이스:

        개발 과정에서 기본 직렬화 타입은 모든 요구 사항을 충족할 수 없습니다.예를 들어 Hadoop 프레임워크 내부에 Bean 객체가 전달되는 경우(기본 데이터 타입(특정 클래스)이 아닌 ----해당 Hadoop 타입이 없음), 그런 다음 개체는 직렬화 인터페이스를 구현해야 합니다.

직렬화를 달성하기 위한 단계:

먼저 간단한 분석을 위해 소스 코드를 살펴보십시오.

쓰기 가능한 인터페이스(아무것도 분석할 수 없는 것 같습니다)

두 가지 방법:

1.쓰기: 직렬화

2.readFields: 역직렬화 

c315f0a572804ddca5aed2d73d226161.png

 (1) 역직렬화 시 null 매개변수 생성자를 반영적으로 호출해야 하므로 null 매개변수 생성자가 있어야 합니다.

public FlowBean() {
	super();
}

(2) 인터페이스 ***에서 두 메서드를 재정의합니다(참고: 역직렬화 순서는 직렬화 순서와 정확히 동일합니다).

                데이터 구조의 대기열과 마찬가지로 선입 선출, 먼저 직렬화 된 다음 직렬화 해제됩니다.

(3) toString() 메서드는 인쇄해야 하기 때문에 다시 작성해야 합니다. 그렇지 않으면 주소가 인쇄됩니다.

(4) 키에 커스텀 빈을 전송해야 하는 경우 MapReduce 상자의 Shuffle 프로세스에서 키를 정렬할 수 있어야 하므로 Comparable 인터페이스도 구현해야 합니다. (예: 이전 블로그에서는 단어 발생 수 계산에서 마지막에 나오는 단어를 영문 26자 순으로 정렬)

샘플 소스 코드(텍스트 문자열)를 살펴보십시오.

1bc7a6fd823244e7b13bb52b20f936c9.png

인터페이스를 구현하려면 위의 그림을 참조하십시오.

WritableComparable<BinaryComparable>

 후속 조치:

0a319f3e22e440a8959684412f2e239b.png

 인터페이스가 Comparable 인터페이스(Java의 API)에서 상속되는지 확인합니다.

직렬화 사례 사례:

케이스 요구 사항:

        총 업스트림 트래픽, 총 다운스트림 트래픽 및 각 휴대폰 번호에서 소비한 총 트래픽을 계산합니다.

(1) 입력 데이터:

1c5aa47d206d48b1a50e2bbaed4f8834.png

 

(2) 입력 데이터 형식:

7 13560436666 120.196.100.99 1116 954 200

id 휴대폰 번호 네트워크 ip 상향 트래픽 하향 트래픽 네트워크 상태 코드

(3) 예상 출력 데이터 형식

13560436666 1116 954 2070

휴대폰 번호 업링크 트래픽 총 다운링크 트래픽

수요 분석:

        먼저 데이터를 입력하고 데이터를 입력한 후 매퍼 단계로 이동해야 합니다---"축소 단계---"출력 단계

매퍼 단계:

kv를 먼저 입력하는 것을 고려하십시오(k --- 오프셋 v는 데이터 행임).

출력(kv)은 감소의 입력(kv)입니다. 트래픽은 bean 클래스(커스텀 객체)를 캡슐화한 다음 전송을 직렬화해야 합니다.

출력(kv)도 (휴대전화번호, 빈클래스)

MapperReduce 프로그램을 작성하십시오.
   

1.FlowBean 코드:

package com.tangxiaocong.mapreduce.writable;

import org.apache.hadoop.io.Writable;

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

/*
*
* 定义bean类
* 需要实现writable
* 重写序列化和反序列化方法
* 重写空参构造
* 重写tostring方法
*
* */
public class FlowBean  implements Writable {
   private  long upFlow;
    private  long downFlow;
    private  long sumFlow;

    public long getUpFlow() {
        return upFlow;
    }

    public void setUpFlow(long upFlow) {
        this.upFlow = upFlow;
    }

    public long getDownFlow() {
        return downFlow;
    }

    public void setDownFlow(long downFlow) {
        this.downFlow = downFlow;
    }

    public long getSumFlow() {
        return sumFlow;
    }

    public void setSumFlow(long sumFlow) {
        this.sumFlow = sumFlow;
    }
    public void setSumFlow() {
        this.sumFlow = this.downFlow+this.upFlow;
    }
    //生成空参构造函数由于反射  快捷键alt   + insert

    public FlowBean() {
    }

    @Override
    public void write(DataOutput out) throws IOException {
        //序列化方法
        //  向缓冲流中写入Long类型的数据
        out.writeLong(upFlow);
        out.writeLong(downFlow);
        out.writeLong(sumFlow);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
//反序列化方法
        //读取缓冲区中数据
        this.upFlow= in.readLong();
        this.downFlow= in.readLong();
        this.sumFlow= in.readLong();
    }

    @Override
    public String toString() {
        return upFlow + "\t"+downFlow +"\t"+ sumFlow ;
    }
}

        2. 매퍼 코드:

package com.tangxiaocong.mapreduce.writable;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class FlowMapper extends Mapper<LongWritable, Text,Text,FlowBean> {

    private Text outK=new Text();
    private  FlowBean outV=new FlowBean();  //调用的无参构造函数

    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, FlowBean>.Context context) throws IOException, InterruptedException {
        //1 获取一行
        //1	13736230513	192.196.100.1	www.atguigu.com	2481	24681	200

        String s = value.toString();// 将数据转换成string
        //2 进行切割

        String[] split = s.split("\t"); //将数据按写入形式进行切割
        //3 抓取想要的数据
        //根据角标获取  手机号  上行流量  下行流量


        String phone = split[1];
        String up = split[split.length - 3];//  不能正序 因为有的属性是没有字段的
        String down = split[split.length - 2];
//     封装输出的kv

        outK.set(phone);
        outV.setUpFlow(Long.parseLong(up));//  up为string类型
        outV.setDownFlow(Long.parseLong(down));
        outV.setSumFlow();          //

        //写出
        context.write(outK,outV);
    }
}

3. 코드 줄이기:

package com.tangxiaocong.mapreduce.writable;

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

import java.io.IOException;

public class FlowReducer extends Reducer  <Text,FlowBean,Text,FlowBean>{
   private FlowBean outv=new FlowBean();


    @Override
    protected void reduce(Text key, Iterable<FlowBean> values, Reducer<Text, FlowBean, Text, FlowBean>.Context context) throws IOException, InterruptedException {

         long totalUp=0;
         long totaldown=0;
         
        //分析   传入TEXT  为手机号  后边为集合(Bean类的对象的集合)输出还是一个一个bean类  (每个手机号的总和)
        for (FlowBean value : values) {  //传入的参数是同一个key的
            totalUp+=value.getUpFlow();
            totaldown+=value.getDownFlow();
        }
        //  现在求出的是每个手机号的总的上行流量  下行流量
            //封装  key不需要
        //outv
    outv.setUpFlow(totalUp);
    outv.setDownFlow(totaldown);
    outv.setSumFlow();
    //写出
        context.write(key,outv);
    }
}

4. 드라이버 코드:

package com.tangxiaocong.mapreduce.writable;

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

public class FlowDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //获取JOB
        Configuration entries = new Configuration();
        Job job = Job.getInstance(entries);

        job.setJarByClass(FlowDriver.class);
        //关联mapper  和reduce
        job.setMapperClass(FlowMapper.class);
        job.setReducerClass(FlowReducer.class);

        //设置mapper  输出的key 和value
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(FlowBean.class);

        // 设置最终的数据输出的key和value 类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class);

        //设置数据的输入路径和输出路径
        FileInputFormat.setInputPaths(job, new Path("D:\\hadoop\\phone_data.txt"));
        FileOutputFormat.setOutputPath(job, new Path("D:\\hadoop\\output3"));
        //提交job
        boolean b = job.waitForCompletion(true);
        System.exit(b ? 0 : 1);

    }

}

 마지막 실행  

버그가 있었는데 디버깅 2시간만에 드라이버 클래스에서 매퍼 클래스를 kv 형식으로 출력하도록 설정해서 답이 나왔는데 에러가 나서 매칭이 안되네요. 

이제 올바르게 작동합니다

a82371d2c82347b69dc78443de46502a.png

 2068443796d04721a34960b9e5f714c6.png

 41784ae70e2f44ee8b47682f7f208c25.png

 

 

 

추천

출처blog.csdn.net/m0_61469860/article/details/129650133