Hadoop实践(三)---Hadoop数据类型

适合Hadoop的数据类型

Hadoop使用派生于Writable接口的类作为MapReduce计算的数据类型,这些数据类型用于整个MapReduce计算流的数据吞吐过程,这个过程从读取输入数据开始,到传输map和reduce任务之间的中间数据,一直到最后写入输出数据为止;为输入数据、中间数据和输出数据选择合适的Writable数据类型面对MapReduce程序的可编程性和性能有很大的影响

  1. 为了用作MapReduce计算的value数据类型,数据类型必须实现org.apache.hadoop.io.Writable接口;Writable接口定义了当需要数据传输和数据存储时,Hadoop应该如何序列化和反序列化

  2. 为了用作MapReduce计算的key数据类型,数据类型必须实现org.apache.hadoop.io.WritableComparable<T>接口,除了Writable接口的功能之外,有一种WritableComparable接口更进一步定义了如何将这种类型的键相互比较,以达到排序的目的

Hadoop带有一些预定于的类用于实现WritableComparable,包括基本数据类型的封装类:

描述
BooleanWritable 标准布尔变量的封装
ByteWritable 单字节数的封装
DoubleWritable 双字节数的封装
FloatWritable 浮点数的封装
IntWritable 整数的封装
LongWritable 长整型的封装
Text 使用UTF-8格式的文本封装
NullWritable 无键值时的占位符

1.使用泛型类型变量为mapper的键值对指定输入数据类型(键:LongWritable,值:Text)和输出数据类型(键:Text,值:IntWritable)

public class SampleMapper extends Mapper<LongWritable,Text,Text,IntWritable>{
   
    public void map(LongWritable key, Text value,Context context). . .{
        . . .
    }
}

2.使用通用型变量为reducer的键值对指定输入数据类型(键:Text,值:IntWritable)和输出数据类型(键:Text,值:IntWritable)【reducer的输入键值对数据类型应该和mapper的输出键值对数据类型相匹配】

public class Reduce extends Reducer<Text,IntWritable,Text,IntWritable>{
   
    public void reduce(Text key, IntWritable value,Context context). . .{
        . . .
    }
}

3.使用Job对象指定MapReduce计算输出数据类型,当mapper和reducer的输出类型相同时:

Job job = new Job(. . .);
(Job job = Job.getInstance();)
. . .
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);

4.当mapper和reducer的输出类型相同时:

job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);

Hadoop提供一些基本数据类型,IntWritable,LongWritable,BooleanWritable,FloatWritable,ByteWritable,这是它们各自的Java基本数据类型的Writable版本,可以使用这些类型作为key类型和value类型

下面是几种Hadoop内置的数据类型,可以作为作为key类型和value类型:

Text:存储UTF8文本
BytesWritable:存储一个字节序列
VIntWritable和VLongWritable:存储变长整型和长整型值
NullWritable:这是零长度的Writable类型(可以在不希望使用key或value类型的时候使用)

下面是Hadoop内置的集合数据类型【只能作为value类型】:

ArrayWritable:存储属于Writable类型的值数组(要使用ArrayWritable类型作为reduce输入的value类型,需要创建ArrayWritable的子类来指定存储在其中的Writable值的类型):

 public class LongArrayWritable extends ArrayWritable{
    
     public LongArrayWritable(){
         super(LongWritable.class);
    }
}

TwoDArrayWritable:存储属于同一个Writable类型的值矩阵(要使用TwoDArrayWritable类型作为reduce输入的value类型,需要创建与ArrayWritable类型相似的TwoDArrayWritable类型的子类来指定存储的值的类型)
MapWritable:存储键值对的映射(键和值应该是Writable数据类型)
SortedMapWritable:存储键值对的有序映射(键应该事先WritableComparable接口)

实现自定义的Hadoop Writable数据类型

通过org.apache.hadoop.io.Writable接口编写一个定制Writable数据类型用于定义数据类型的序列化格式(基于Writable的接口类型可以用来作为Hadooop MapReduce计算的value类型)

假设日志包含5个部分:请求的主机,时间戳,请求的URL,相应大小,HTTP状态码,如下:

192.168.0.2 -- [01/Jul.1995:00:00:01-0400] "GET/history/appollo/HTTP/1.0" 200 6245

实现日志条目的自定义Hadoop Writable数据类型的步骤:
1.血一个新的LogWritable类实现org.apache.hadoop.io.Writable接口

public class LogWritable implements Writable{
    private Text userIP;
    private Text timestamp;
    private Text request;
    private IntWritable responseSize;
    private IntWritable status;

    public LogWritable(){
        this.userIP = new Text();
        this.timestamp = new Text();
        this.request = new Text();
        this.responseSize = new IntWritable();
        this.status = new IntWritable();
    }
    public void readFields(DataInput in)throws IOException{
        userIP.readFields(in);
        timestamp.readFields(in);
        request.readFields(in);
        responseSize.readFields(in);
        status.readFields(in);
    }
    public void write(DataOuput out)throws IOException{
        userIP.write(out);
        timestamp.write(out);
        request.write(out);
        responseSize.write(out);
        status.write(out);
    }
    . . .//getters and setters for the fields
}

2.使用新的LogWritable类型作为MapReduce计算的value类型
例如,使用LogWritable类型作为Map输出值的类型

public class LogProcessMap extends Mapper<LongWritable,Text,Text,LogWritable>{
   
    ...
}
public class LogProcessReduce extends Reducer<Text,LogWritable,Text,IntWritable>{
   
    public void reduce(Text key,Iterable<LogWritable> values,Context context){
        ...
    }
}

3.配置相应的作用的输出类型

Job job = new Job(...);
(Job job = Job.getInstance();)
...
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LogWritable.class);

工作原理
Writable接口包含2个方法:readFields()he write(),在readFields()方法中我们反序列化输入数据,并填充Writable对象的字段:

public void readFields(DataInput in)throws IOException{
        userIP.readFields(in);
        timestamp.readFields(in);
        request.readFields(in);
        responseSize.readFields(in);
        status.readFields(in);
    }

在上面的示例中,使用Writable类型作为自定义的Writable类型的字段,并且使用readFields()方法从DataInput对象的数据字段中反序列化数据,【当然也可以使用Java的基本数据类型作为Writabel类型的字段,并使用DataInput对象的想要读取方法从基础流中读取值】,如下面的代码所示:

int responseSize = in.readInt();
String userIP = in.readUTF();
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值