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

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

本文完!

目录
相关文章
|
20天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
2月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
1月前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
29 0
|
3月前
|
JSON fastjson Java
niubility!即使JavaBean没有默认无参构造器,fastjson也可以反序列化。- - - - 阿里Fastjson反序列化源码分析
本文详细分析了 Fastjson 反序列化对象的源码(版本 fastjson-1.2.60),揭示了即使 JavaBean 沲有默认无参构造器,Fastjson 仍能正常反序列化的技术内幕。文章通过案例展示了 Fastjson 在不同构造器情况下的行为,并深入探讨了 `ParserConfig#getDeserializer` 方法的核心逻辑。此外,还介绍了 ASM 字节码技术的应用及其在反序列化过程中的角色。
83 10
|
3月前
|
存储 XML JSON
用示例说明序列化和反序列化
用示例说明序列化和反序列化
|
3月前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!
|
3月前
|
JSON 安全 编译器
扩展类实例的序列化和反序列化
扩展类实例的序列化和反序列化
37 1
|
3月前
|
XML Dubbo Java
分布式-序列化,反序列化
分布式-序列化,反序列化