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 文末

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

本文完!

目录
相关文章
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
202 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
228 1
|
5月前
|
JSON 人工智能 Go
在Golang中序列化JSON字符串的教程
在Golang中,使用`json.Marshal()`可将数据结构序列化为JSON格式。若直接对JSON字符串进行序列化,会因转义字符导致错误。解决方案包括使用`[]byte`或`json.RawMessage()`来避免双引号被转义,从而正确实现JSON的序列化与反序列化。
281 7
|
6月前
|
存储 Java 编译器
说一说关于序列化/反序列化中的细节问题
我是小假 期待与你的下一次相遇 ~
126 1
|
6月前
|
JSON Java 数据库连接
|
7月前
|
存储 安全 IDE
说一说序列化与反序列化中存在的问题
本文详细解析了Java中的序列化机制,包括序列化的概念、实现方式及应用场景。通过Student类的实例演示了对象的序列化与反序列化过程,并分析了`Serializable`接口的作用以及`serialVersionUID`的重要意义。此外,文章还探讨了如何通过自定义`readObject()`方法增强序列化的安全性,以及解决可序列化单例模式中可能产生的多实例问题。最后提供了代码示例和运行结果,帮助读者深入理解序列化的原理与实践技巧。
199 2
|
7月前
|
JSON JavaScript 前端开发
Go语言JSON 序列化与反序列化 -《Go语言实战指南》
本文介绍了 Go 语言中使用 `encoding/json` 包实现 JSON 与数据结构之间的转换。内容涵盖序列化(`Marshal`)和反序列化(`Unmarshal`),包括基本示例、结构体字段标签的使用、控制字段行为的标签(如 `omitempty` 和 `-`)、处理 `map` 和切片、嵌套结构体序列化、反序列化未知结构(使用 `map[string]interface{}`)以及 JSON 数组的解析。最后通过表格总结了序列化与反序列化的方法及类型要求,帮助开发者快速掌握 JSON 数据处理技巧。
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
547 1
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
624 0