Hive教程(06)- Hive SerDe序列化与反序列化

简介: Hive教程(06)- Hive SerDe序列化与反序列化

01 引言

在前面的教程,已经初步了解了Hive数据模型、数据类型和操作的命令,有兴趣的同学可以参阅:

既然我们知道的使用hive将数据存储到的地方(数据模型)、存的数据类型以及存的方式(命令),那么这里会提出一个疑问,数据最终是会存入一个文件的,但是数据的来源是一个“对象”,这个过程是怎么转换的?本文来讲解下。

02 SerDe

2.1 概念

什么是SerDe?其实他代表两种含义的缩写:

  • Serializer序列化:是对象转换成字节序列的过程
  • Deserializer反序列化:是字节序列转换成对象的过程

序列化与反序列化的过程如下:

  • Serializer序列化:数据行对象(Row object)—> 序列化 —> OutputFileFormate —> HDFS 文件
  • Deserializer反序列化HDFS 文件 —> InputFileFormate —> 反序列化 —> 数据行对象(Row object

SerDe 可以让Hive从表中读取数据,然后以任意自定义格式把数据写回 HDFS,并可以根据具体的数据格式开发自定义的SerDe 实现。

Hive创建表时,指定数据的序列化和反序列化方式,模板如下:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)]
INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]

2.2 分类

Hive SerDe分为内置的自定义的,下面来讲讲。

2.2.1 内置 SerDe 类型

Hive 使用下面的 FileFormat 类型来读写 HDFS 文件

  • TextInputFormat/HiveIgnoreKeyTextOutputFormat:该格式用于读写文本文件格式的数据。
  • SequenceFileInputFormat/SequenceFileOutputFormat
    :该格式用于读写 Hadoop 的序列文件格式。

内置的SerDe类型分类有:

  • Avro
  • ORC
  • RegEx
  • Thrift
  • Parquet
  • CSV
  • JsonSerDe
2.2.1.1 MetadataTypedColumnsetSerDe

这个 SerDe 类型用于读写以某个分隔符分隔的记录。比如使用逗号分隔符的记录(CSV),tab 键分隔符的记录。

2.2.1.2 LazySimpleSerDe

这个是默认的 SerDe 类型。读取与 MetadataTypedColumnsetSerDeTCTLSeparatedProtocol相同的数据格式。

可以用这个 Hive SerDe类型,它是以惰性的方式创建对象的,因此具有更好的性能。

Hive 0.14.0版本以后,在读写数据时它支持指定字符编码。例如:

ALTER TABLE person SET SERDEPROPERTIES (‘serialization.encoding’=’GBK’)

如果把配置属性 hive.lazysimple.extended_boolean_literal设置为trueHive 0.14.0以后版本),LazySimpleSerDe可以把‘T’, ‘t’, ‘F’, ‘f’, ‘1’, and ‘0’视为合法的布尔字面量。而该配置默认是false的,因此它只会把‘True’‘False’视为合法的布尔字面量。

2.2.1.3 Thrift SerDe

读写Thrift序列化对象,可以使用这种 Hive SerDe类型。需要确定的是,对于 Thrift对象,类文件必须先被加载。

2.2.1.4 动态 SerDe

为了读写 Thrift序列化对象,我们可以使用这种 SerDe类型。

它可以理解 Thrift DDL 语句,所以对象的模式可以在运行时被提供。

另外,它支持许多不同的协议,包括 TBinaryProtocol, TJSONProtocol, TCTLSeparatedProtocol

2.2.2 自定义 SerDe 类型

2.2.2.1 步骤一:自定义SerDe

首先定义一个类, 继承抽象类 AbstractSerDe, 实现 initializedeserialize 两个方法。

注意:下面代码中,Hive 使用 ObjectInspector对象分析行对象的内部结构以及列的结构,具体来说,ObjectInspector给访问复杂的对象提供了一种统一的方式。对象可能以多种格式存储在内存中:

  • Java 类实例,Thrift 或者 原生 Java
  • 标准 Java对象,比如Map字段,我们使用 java.util.List表示StructArray,以及使用java.util.Map
  • 惰性初始化对象

此外可以通过 (ObjectInspector, java 对象) 这种结构表示一个复杂的对象。它为我们提供了访问对象内部字段的方法,而不涉及对象结构相关的信息。出了序列化的目的,Hive 建议为自定义 SerDes 创建自定义的 objectinspectorSerDe有两个构造器,一个无参构造器,一个常规构造器

示例代码:

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.2.2.2 步骤二:hive添加Serde

使用自定义 Serde 类型:

hive > add jar MySerDe.jar
2.2.2.3 步骤三:使用Serde

创建表格时属性 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/'

03 文末

本文主要参考了以下文献:

本文完!

目录
相关文章
|
6天前
|
存储 安全 Java
Java一分钟之-Java序列化与反序列化
【5月更文挑战第14天】Java序列化用于将对象转换为字节流,便于存储和网络传输。实现`Serializable`接口使类可被序列化,但可能引发隐私泄露、版本兼容性和性能问题。要避免这些问题,可使用`transient`关键字、控制`serialVersionUID`及考虑使用安全的序列化库。示例代码展示了如何序列化和反序列化对象,强调了循环引用和未实现`Serializable`的错误。理解并妥善处理这些要点对优化代码至关重要。
15 1
|
6天前
|
JSON 安全 Java
Spring Boot 序列化、反序列化
本文介绍了Spring Boot中的序列化和反序列化。Java提供默认序列化机制,通过实现Serializable接口实现对象到字节流的转换。Spring Boot默认使用Jackson处理JSON,可通过注解和配置自定义规则。然而,序列化可能引发安全问题,建议使用白名单、数据校验和安全库。最佳实践包括使用标准机制、自定义规则及注意版本控制。文章还提醒关注性能并提供了相关参考资料。
68 2
|
6天前
|
XML 存储 JSON
c#XML、JSON的序列化和反序列化,看完你就懂了
c#XML、JSON的序列化和反序列化,看完你就懂了
29 0
|
6天前
|
JSON Java Linux
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
23 2
|
6天前
|
XML 存储 JSON
[计算机网络]---序列化和反序列化
[计算机网络]---序列化和反序列化
|
6天前
|
存储 JSON PHP
python序列化与反序列化
python序列化与反序列化
|
6天前
|
存储 Java 测试技术
滚雪球学Java(22):序列化和反序列化
【4月更文挑战第11天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
35 1
滚雪球学Java(22):序列化和反序列化
|
6天前
|
SQL 存储 安全
每日一道面试题:Java中序列化与反序列化
每日一道面试题:Java中序列化与反序列化
13 0
|
6天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
29 5
|
6天前
|
存储 JSON 安全
Python中对象到文件的序列化和反序列化
【4月更文挑战第2天】在Python编程中,序列化和反序列化是处理对象与文件之间转换的重要技术。序列化是将对象状态转换为可以存储或传输的形式的过程,通常是将对象转换为字节流。反序列化则是将序列化后的形式转换回对象的过程。在Python中,我们可以使用`pickle`模块来轻松地实现对象的序列化和反序列化。

热门文章

最新文章