Hadoop数据类型:
课程结构图:
键/值序列化
序列化:云端键值的序列化,序列化是一个核心.它是将对象转化为字节流的方法;
其目的有:
1. 进程间通信
2. 数据持久性存储
假如说,要从A传输一个对象到B,我们必须要将这个对象转化为二进制流才可以。如果想要将云端的一个对象存到硬盘,那我们也必须要将这个对象转化为二进制流才可以进行存储。
MapReduce框架提供了一种序列化键/值的方法,没有使用Java中的序列化方法。原因:
在Hadoop中,序列化处于核心地位:
1. 因为无论是存储文件还是在计算中传输数据,都需要执行序列化的过程
2. 序列化与反序列化的速度,序列化后的数据大小等都会影响数据传输的速度,以致影响计算的效率。
Hadoop并没有采用Java的序列化机制,而是重新写了一个序列化接口Writable.
紧凑、快速、并允许对自己定义的类加入序列化与反序列化.
Writable
Writable 是Hadoop的核心
1. Hadoop通过它定义了Hadoop中基本的数据类型.
org.apache.hadoop.io.Writable
org.apache.hadoop.io.Writable
public interface Writable {
//序列化输出
void write(DataOutput out) throws IOException;
//反序列化输入
void readFields(DataInput in) throws IOException
}
WritableComparable
这个接口实现了序列化机制,同时增加了比较的功能;
来自两个父接口:Writable, Comparable.
这个接口的定义:
public interface WritableComparable<T> {
write...
readFields...
int compareTo(T o)
}
Hadoop比较器:WritableComparator
它是WritableComparable的通用实现:但同时它还实现了:java.util.Comparator,RawComparator
public class WritableComparator impliments Comparator, RawComparator
功能:
public Interface RawComparator<T>
int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2);
这个接口实现的功能是从两个数据流中去抓取一定长度的内容进行大小的比较.
它其实就实现了对未反序列化对象的读取和比较,可以不需要创建对象就能比较Key值.这样的话,在这个点的速度就提高了;而我们知道对于大数据而言,只要一个细节速度的提升,聚集起来就会是一个大的性能的提升.
基本数据类型
需要注意的是:整个Hadoop或者说整个Mapreduce的处理过程中,数据是被归约成Key或者Value的形式.要么就是Key要么就是Value.
Value:
1. 实现接口Writable
2. 实现其方法write()和readFields()
3. 该数据能被序列化后完成网络传输或文件I/O
Key:
- 实现WritableComparable接口
- 实现其方法write(), readFields(), CompareTo()
- 支持序列化外,还支持比较方法
— IntWritable和LongWritable的readFields()都直接从实现了DataInput接口的输入流中读取二进制数据并分别重构成int型和long型。
— 而write()则直接将int型数据和long型数据直接转换成二进制流。
— IntWritable和LongWritable都含有相应的Comparator内部类,这是用来支持对在不反序列化为对象的情况下对数据流中的数据单位进行直接的比较。
分析列子#IntWritable#
代码:
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.io;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
/** A WritableComparable for ints. */
@InterfaceAudience.Public
@InterfaceStability.Stable
public class IntWritable implements WritableComparable<IntWritable> {
private int value;
public IntWritable() {
}
public IntWritable(int value) {
set(value);
}
/** Set the value of this IntWritable. */
public void set(int value) {
this.value = value;
}
/** Return the value of this IntWritable. */
public int get() {
return value;
}
//实现了整数数据类型的序列化和反序列化
@Override
public void readFields(DataInput in) throws IOException { //从DataInput中把数据读出来,实现了一个反序列化的功能
value = in.readInt();
}
@Override
public void write(DataOutput out) throws IOException { //这里则是把valude这个数值写道Dataoutput这个流中间,实现了序列化的功能
out.writeInt(value);
}
/** Returns true iff <code>o</code> is a IntWritable with the same value. */
@Override
public boolean equals(Object o) {
if (!(o instanceof IntWritable))
return false;
IntWritable other = (IntWritable) o;
return this.value == other.value;
}
@Override
public int hashCode() {
return value;
}
/** Compares two IntWritables. */
@Override
public int compareTo(IntWritable o) {
int thisValue = this.value;
int thatValue = o.value;
return (thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1));
}
@Override
public String toString() {
return Integer.toString(value);
}
/** A Comparator optimized for IntWritable. */
public static class Comparator extends WritableComparator {
public Comparator() {
super(IntWritable.class);
}
@Override
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
int thisValue = readInt(b1, s1);
int thatValue = readInt(b2, s2);
return (thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1));
}
}
static { // register this comparator
WritableComparator.define(IntWritable.class, new Comparator());
}
}
基本类型:
基本类型除了IntWritable以外还有很多其他的基本类型;比如VIntWritable&VLongWritable, 他们的加上了要给V的区别在于他们是变长格式;他们序列化后分别占(1 - 5)或(1 - 9)个字节。当需要编码数值非常小(-127 - 127)*只占一个字节。否则使用第一个字节表示数值的正负和后跟多少个字节。简单的来说就是,加上了V之后原来的固定字节数就变成了变长字节数。
NullWritable:这是一个占位符,序列化长度为0,没有数值从流中读出或者似乎写入流中。
BytesWritable:这是二进制数据数组的封装;
它的序列化过程:
1. 将二进制数据数组的长度(4个字节)写入流中,然后写出二进制数组字节
2. 例:长度为2分别包含3、5的二进制数组序列化为
000000020305
文本类型Text:
- 对Java中String的重写
- Text使用UTF-8编码
- 使用Vint来存储字符串,上限是2GB
Text和String的主要区别:
1. Text类对于Unicode字符采用的是UTF-8编码(是可变长度的),而不是使用Java Character类的UTF-16编码
2. String中的indexOf()方法返回字符类型的索引,Text的find()返回的是字节偏移量;String以字符为单位,而后者以字节为单位;其实每个字符所占的字节量是不一样的.
3. Text的toString(),用于转换Text为String
下面这个例子展示标准Text使用的方法: #MyMaperText#
package experment4;
import org.apache.hadoop.io.Text;
public class MyMapreText {
public static void strings(){
String s="\u0041\u00DF\u6771\uD801\uDC00"; //最后一个字符是一个候补字符,占2个字符
System.out.println(s);
System.out.println(s.length()); //取字符串的长度
System.out.println(s.indexOf("\u0041"));
System.out.println(s.indexOf("\u00DF"));
System.out.println(s.indexOf("\u6771"));
System.out.println(s.indexOf("\uD801\uDC00"));
//一个候补字符,需要2个Java char 类型表示
}
public static void texts(){
Text t = new Text("\u0041\u00DF\u6771\uD801\uDC00");
System.out.println(t.toString());
System.out.println(t.getLength()); //UTF-8字节数
System.out.println(t.find("\u0041"));//1个字节41
System.out.println(t.find("\u00DF"));//2个字节C391
System.out.println(t.find("\u6771"));//3个字节 E69DB1
System.out.println(t.find("\uD801\uDC00"));//4个字节 F0909080
}
public static void main(String args[]){
strings();
System.out.println();
texts();
}
}
运行效果:
从这个程序可以看出String和Text的一些不同,一个是一字符为单位,另一个是以字节为单位.
Object Writable
— 是对java基本类型的一个通用封装.
ArrayWritable &TwoDArrayWritable
MapWritable & SortedMapWritable
自定义数据类型
实现自己的Hadoop数据类型
— key, 实现WritableComparable
— value, 实现Writalbe
例子:
#Edge.java#
package hadoop.datetype;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
/**
* 表示一个网络的边的数据类型(起点,终点)
*
*/
public class Edge implements WritableComparable<Edge> {
private String departureNode; //出发结点
private String arrivalNode; //达到结点
public String getDepartureNode() { return departureNode;}
@Override
public void readFields(DataInput in) throws IOException {
departureNode = in.readUTF();
arrivalNode = in.readUTF();
}
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(departureNode);
out.writeUTF(arrivalNode);
}
@Override
public int compareTo(Edge o) {
return (departureNode.compareTo(o.departureNode) != 0)
? departureNode.compareTo(o.departureNode)
: arrivalNode.compareTo(o.arrivalNode);
}
}
#Numpair.java#
package hadoop.datetype;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.WritableComparable;
/**
* 一个整数对的表示,可以用来表示单词出现的位置
* 可以用第一个LongWritable代表行数
* 第二个LongWritable代表该行的第几个单词
*/
public class NumPair implements WritableComparable<NumPair> {
private LongWritable line;
private LongWritable location;
@Override
public void readFields(DataInput arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void write(DataOutput arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public int compareTo(NumPair o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
public NumPair() {
set(new LongWritable(0), new LongWritable(0));
}
public void set(LongWritable first, LongWritable second) {
this.line = first;
this.location = second;
}
public NumPair(LongWritable first, LongWritable second) {
set(first, second);
}
public NumPair(int first, int second) {
set(new LongWritable(first), new LongWritable(second));
}
public LongWritable getLine() {
return line;
}
public LongWritable getLocation() {
return location;
}
// @Override
// public void readFields(DataInput in) throws IOException {
// line=in.readLong();
// line.set(in.readLong());
//
// line.readFields(in);
// location.readFields(in);
// }
// @Override
// public void write(DataOutput out) throws IOException {
// line.write(out);
// location.write(out);
// }
public boolean equals(NumPair o) {
if ((this.line == o.line) && (this.location == o.location))
return true;
return false;
}
// @Override
// public int hashCode() {
// return line.hashCode() * 13 + location.hashCode();
// }
//
// @Override
// public int compareTo(NumPair o) {
// if ((this.line == o.line) && (this.location == o.location))
// return 0;
// return -1;
// }
}