一、SerDe的概念
SerDe 是两个单词的拼写 serialized(序列化) 和 deserialized(反序列化)。
对象序列化:当进程在进行远程通信时,彼此可以发送各种类型的数据,无论是什么类型的数据都会以 二进制序列的形式在网络上传送。发送方需要把对象转化为字节序列才可在网络上传输。
对象的反序列化:接收方则需要把字节序列恢复为对象。
Hive的反序列化是对key/value反序列化成hive table的每个列的值。Hive可以方便 的将数据加载到表中而不需要对数据进行转换,这样在处理海量数据时可以节省大量的时间。
二、序列化与反序列化的过程
Serializer序列化:数据行对象(Row object)—> 序列化 —> OutputFileFormate —> HDFS 文件
Deserializer反序列化:HDFS 文件 —> InputFileFormate —> 反序列化 —> 数据行对象(Row object)
三、Hive 的 SerDe 分类
1,内置 SerDe 类型
Hive 读写 HDFS 文件的 FileFormat 类型:
(1)TextInputFormat/HiveIgnoreKeyTextOutputFormat
读写文本文件格式的数据。
(2)SequenceFileInputFormat/SequenceFileOutputFormat
读写 Hadoop 的序列文件格式。
Hive 序列化和反序列化数据的SerDe 类:
(1)MetadataTypedColumnsetSerDe
用于读写以某个分隔符分隔的记录。比如使用逗号分隔符的记录(CSV),tab 键分隔符的记录。
(2)LazySimpleSerDe
默认的 SerDe 类型。读取与 MetadataTypedColumnsetSerDe 和 TCTLSeparatedProtocol 相同的数据格式,可以用这个 Hive SerDe 类型。它是以惰性的方式创建对象的,因此具有更好的性能。在 Hive 0.14.0 版本以后,在读写数据时它支持指定字符编码。
示例:
ALTER TABLE person SET SERDEPROPERTIES (‘serialization.encoding’=’GBK’)
如果把配置属性 hive.lazysimple.extended_boolean_literal 设置为 true(Hive 0.14.0 以后版本),LazySimpleSerDe 可以把 ‘T’, ‘t’, ‘F’, ‘f’, ‘1’, and ‘0’ 视为合法的布尔字面量。而该配置默认是 false 的,因此它只会把 ‘True’ 和 ‘False’ 视为合法的布尔字面量。
(3)Thrift SerDe
读写 Thrift 序列化对象,可以使用这种 Hive SerDe 类型。需要确定的是,对于 Thrift 对象,类文件必须先被加载。
(4)动态 SerDe
为了读写 Thrift 序列化对象,我们可以使用这种 SerDe 类型。它可以理解 Thrift DDL 语句,所以对象的模式可以在运行时被提供。另外,它支持许多不同的协议,包括 TBinaryProtocol, TJSONProtocol, TCTLSeparatedProtocol。
2,自定义 SerDe 类型
如果 Hive 的自定义 Serde 类型不能满足你的需求,你可以自己定义自己的 SerDe 类型。
(1)定义一个类
定义一个类, 继承抽象类 AbstractSerDe, 实现 initialize 和 deserialize 两个方法。
示例代码如下:
package com.coder4.hive;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.serde.Constants;
import org.apache.hadoop.hive.serde2.AbstractSerDe;
import org.apache.hadoop.hive.serde2.SerDeException;
import org.apache.hadoop.hive.serde2.SerDeStats;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
public class MySerDe extends AbstractSerDe {
// params
private List<String> columnNames = null;
private List<TypeInfo> columnTypes = null;
private ObjectInspector objectInspector = null;
// seperator
private String nullString = null;
private String lineSep = null;
private String kvSep = null;
@Override
public void initialize(Configuration conf, Properties tbl)
throws SerDeException {
// Read sep
lineSep = "\n";
kvSep = "=";
nullString = tbl.getProperty(Constants.SERIALIZATION_NULL_FORMAT, "");
// Read Column Names
String columnNameProp = tbl.getProperty(Constants.LIST_COLUMNS);
if (columnNameProp != null && columnNameProp.length() > 0) {
columnNames = Arrays.asList(columnNameProp.split(","));
} else {
columnNames = new ArrayList<String>();
}
// Read Column Types
String columnTypeProp = tbl.getProperty(Constants.LIST_COLUMN_TYPES);
// default all string
if (columnTypeProp == null) {
String[] types = new String[columnNames.size()];
Arrays.fill(types, 0, types.length, Constants.STRING_TYPE_NAME);
columnTypeProp = StringUtils.join(types, ":");
}
columnTypes = TypeInfoUtils.getTypeInfosFromTypeString(columnTypeProp);
// Check column and types equals
if (columnTypes.size() != columnNames.size()) {
throw new SerDeException("len(columnNames) != len(columntTypes)");
}
// Create ObjectInspectors from the type information for each column
List<ObjectInspector> columnOIs = new ArrayList<ObjectInspector>();
ObjectInspector oi;
for (int c = 0; c < columnNames.size(); c++) {
oi = TypeInfoUtils
.getStandardJavaObjectInspectorFromTypeInfo(columnTypes
.get(c));
columnOIs.add(oi);
}
objectInspector = ObjectInspectorFactory
.getStandardStructObjectInspector(columnNames, columnOIs);
}
@Override
public Object deserialize(Writable wr) throws SerDeException {
// Split to kv pair
if (wr == null)
return null;
Map<String, String> kvMap = new HashMap<String, String>();
Text text = (Text) wr;
for (String kv : text.toString().split(lineSep)) {
String[] pair = kv.split(kvSep);
if (pair.length == 2) {
kvMap.put(pair[0], pair[1]);
}
}
// Set according to col_names and col_types
ArrayList<Object> row = new ArrayList<Object>();
String colName = null;
TypeInfo type_info = null;
Object obj = null;
for (int i = 0; i < columnNames.size(); i++) {
colName = columnNames.get(i);
type_info = columnTypes.get(i);
obj = null;
if (type_info.getCategory() == ObjectInspector.Category.PRIMITIVE) {
PrimitiveTypeInfo p_type_info = (PrimitiveTypeInfo) type_info;
switch (p_type_info.getPrimitiveCategory()) {
case STRING:
obj = StringUtils.defaultString(kvMap.get(colName), "");
break;
case LONG:
case INT:
try {
obj = Long.parseLong(kvMap.get(colName));
} catch (Exception e) {
}
}
}
row.add(obj);
}
return row;
}
@Override
public ObjectInspector getObjectInspector() throws SerDeException {
return objectInspector;
}
@Override
public SerDeStats getSerDeStats() {
return null;
}
@Override
public Class<? extends Writable> getSerializedClass() {
return Text.class;
}
@Override
public Writable serialize(Object arg0, ObjectInspector arg1)
throws SerDeException {
return null;
}
}
(2)使用自定义 Serde 类型
hive > add jar MySerDe.jar
创建表格时属性 row fromat 指定自定义的 SerDe 类。
CREATE EXTERNAL TABLE IF NOT EXISTS teacher (
id BIGINT,
name STRING,
age INT)
ROW FORMAT SERDE 'com.coder4.hive.MySerDe'
STORED AS TEXTFILE
LOCATION '/usr/hive/text/'
文章参考:https://www.hadoopdoc.com/hive/hive-serde