Hive基础(一)

Hive简介

Hive是基于Hadoop的一个数据仓库工具,能够将结构化的数据文件映射为数据库表,并提供类SQL查询功能。其本质是将SQL转换为MapReduce或Spark任务进行运算,底层依赖HDFS提供数据存储。从某种意义上来说,Hive可以被理解为一个将SQL转换为MapReduce/Spark任务的工具。

Hive的特点:

  • 简单易用,提供了类似SQL的查询语言(HQL),使得精通SQL但不熟悉Java编程的人员也能轻松上手,高效地进行大数据分析。
  • 高度灵活,支持用户自定义函数(UDF)和自定义存储格式,能够满足多样化的业务需求。
  • 强大的扩展性,专为超大数据集设计,集群扩展简单,能够轻松应对海量数据的存储和计算需求。
  • 统一的元数据管理,元数据可与Presto、Impala、SparkSQL等工具共享,便于数据的统一管理和跨工具查询。
  • 执行延迟较高,Hive的计算模式决定了其执行延迟相对较高,不适合用于数据的实时处理,但非常适用于海量数据的离线处理场景。

使用Hive的主要原因包括以下几点:

  1. 降低开发成本:学习MapReduce的成本较高,且项目周期通常较短,MapReduce实现复杂查询逻辑的开发难度较大,而Hive采用类似SQL的操作接口,能够快速开发,避免书写MapReduce,减少学习成本,同时提供功能扩展。
  2. 提高开发效率:Hive的类SQL语法使得数据处理更加直观,开发人员可以快速上手,减少开发时间,提升开发效率。

Hive架构

  1. CLI & Thrift & WebGU:
    • CLI,通过Hive命令行的的方式来操作数据
    • Thrift/JDBC,通过Thrift协议按照标准的JDBC的方式操作数据
    • WebGUI,通过浏览器访问Hive
  2. Metastore:

在Hive中,表名、表结构、字段名、字段类型、表的分隔符等统一被称为元数据。所有的元数据默认存储在Hive内置的Derby数据库中,但由于Derby只能有一个实例,也就是说不能有多个命令行客户端同时访问,所以在实际生产环境中,通常使用MySQL代替Derby。

Hive进行的是统一的元数据管理,即在Hive上创建了一张表,在Presto/Impala/SparkSQL中都是可以直接使用的,它们会从Metastore中获取统一的元数据信息;同样的,在Presto/Impala/SparkSQL中创建一张表,在Hive中也可以直接使用。

  1. Hive在执行一条HQL的时候,会经过以下步骤:
    • 语法解析:Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树ASTTree
    • 语义解析:遍历ASTTree,抽象出查询的基本组成单元QueryBlock
    • 生成逻辑执行计划:遍历QueryBlock,翻译为执行操作树OperatorTree
    • 优化逻辑执行计划:逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
    • 生成物理执行计划:遍历OperatorTree,翻译为MapReduce任务
    • 优化物理执行计划:物理层优化器进行MapReduce任务的变换,生成最终的执行计划

数据类型

基本数据类型

Hive支持的主要基本数据类型如下:

大类 类型
Integers(整型) TINYINT - 1字节的有符号整数 SMALLINT - 2字节的有符号整数 INT - 4字节的有符号整数 BIGINT - 8字节的有符号整数
Boolean(布尔型) BOOLEAN - TRUE/FALSE
Floating point numbers(浮点型) FLOAT - 单精度浮点型 DOUBLE - 双精度浮点型
Fixed point numbers(定点数) DECIMAL - 用户自定义精度定点数,比如DECIMAL(7,2)
String types(字符串) STRING - 指定字符集的字符序列 VARCHAR - 具有最大长度限制的字符序列 CHAR - 固定长度的字符序列
Date and time types(日期时间类型) TIMESTAMP - 时间戳 TIMESTAMP WITH LOCAL TIME ZONE - 时间戳,纳秒精度 DATE - 日期类型
Binary types(二进制类型) BINARY - 字节序列

TIMESTAMP和TIMESTAMP WITH LOCAL TIME ZONE的区别如下:

  • TIMESTAMP:提交什么时间就保存什么时间,查询时也不做任何转换
  • TIMESTAMP WITH LOCAL TIME ZONE:用户提交时间给数据库时,会被转换成数据库所在的时区来保存;查询时则按照查询客户端的不同,转换为查询客户端所在时区的时间

隐式转换

Hive中基本数据类型遵循以下的层次结构,按照这个层次结构,子类型到祖先类型允许隐式转换,例如INT类型的数据允许隐式转换为BIGINT类型。额外需要注意的是,按照类型层次结构允许将STRING类型隐式转换为DOUBLE类型。

复杂类型

类型 描述 示例
STRUCT 类似于对象,是字段的集合,字段的类型可以不同,可以使用名称.字段名方式进行访问 STRUCT (‘xiaoming’, 12 , ‘2018-12-12’)
MAP 键值对的集合,可以使用名称[key]的方式访问对应的值 map(‘a’, 1, ‘b’, 2)
ARRAY 数组是一组具有相同类型和名称的变量的集合,可以使用名称[index]访问对应的值 ARRAY(‘a’, ‘b’, ‘c’, ‘d’)

示例

如下是一个基本数据类型和复杂数据类型的使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE employees (
employee_id INT COMMENT '员工编号,唯一标识一个员工',
name STRING COMMENT '员工姓名',
age INT COMMENT '员工年龄',
salary DOUBLE COMMENT '员工薪资,单位为元',
is_active BOOLEAN COMMENT '是否在职,TRUE 表示在职,FALSE 表示离职',
join_date DATE COMMENT '员工入职日期',
skills ARRAY<STRING> COMMENT '员工技能列表,每个技能为一个字符串',
contact_info STRUCT<phone:STRING, email:STRING> COMMENT '员工联系方式,包含电话和电子邮件',
work_experience ARRAY<STRUCT<company:STRING, position:STRING, duration:STRING>> COMMENT '员工工作经历,每个工作经历包含公司名称、职位和工作时长',
projects MAP<STRING, ARRAY<STRING>> COMMENT '员工参与的项目,键为项目名称,值为项目中的角色列表'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':'
COMMENT '员工信息表,存储员工的基本信息、技能、联系方式、工作经历和参与项目';

内容格式

当数据存储在文本文件中,必须按照一定格式区别行和列,如使用逗号作为分隔符的CSV文件或者使用制表符作为分隔值的TSV文件。但此时也存在一个缺点,就是正常的文件内容中也可能出现逗号或者制表符。因此,Hive默认使用了几个平时很少出现的字符,这些字符一般不会作为内容出现在文件中。Hive默认的行和列分隔符如下表所示:

分隔符 描述
\n 对于文本文件来说,每行是一条记录,所以可以使用换行符来分割记录
^A (Ctrl+A) 分割字段 (列),在CREATE TABLE语句中也可以使用八进制编码\001来表示
^B 用于分割ARRAY或者STRUCT中的元素,或者用于MAP中键值对之间的分割,在CREATE TABLE语句中也可以使用八进制编码\002表示
^C 用于MAP中键和值之间的分割,在CREATE TABLE语句中也可以使用八进制编码\003表示

存储格式

Hive会在HDFS为每个数据库上创建一个目录,数据库中的表是该目录的子目录,表中的数据会以文件的形式存储在对应的表目录下。Hive支持以下几种文件存储格式:

格式 说明
TextFile 存储为纯文本文件,这是Hive默认的文件存储格式,这种存储方式数据不做压缩,磁盘开销大,数据解析开销大
SequenceFile SequenceFile是Hadoop API提供的一种二进制文件,它将数据以<key,value>的形式序列化到文件中,这种二进制文件内部使用Hadoop的标准的Writable接口实现序列化和反序列化,它与Hadoop API中的MapFile是互相兼容的;Hive中的SequenceFile继承自Hadoop API的SequenceFile,不过它的key为空,使用value存放实际的值,这样是为了避免MR在运行map阶段进行额外的排序操作
RCFile RCFile文件格式是FaceBook开源的一种Hive的文件存储格式,首先将表分为几个行组,对每个行组内的数据按列存储,每一列的数据都是分开存储
ORC Files ORC是在一定程度上扩展了RCFile,是对RCFile的优化
Avro Files Avro是一个数据序列化系统,设计用于支持大批量数据交换的应用,它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro提供的机制使动态语言可以方便地处理Avro数据
Parquet Parquet是基于Dremel的数据模型和算法实现的,面向分析型业务的列式存储格式,它通过按列进行高效压缩和特殊的编码技术,从而在降低存储空间的同时提高了IO效率

存储格式通常在创建表的时候使用STORED AS参数指定:

1
2
3
4
5
6
CREATE TABLE page_view(viewTime INT, userid BIGINT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
STORED AS SEQUENCEFILE;

各个存储文件类型指定方式如下:

1
2
3
4
5
6
STORED AS TEXTFILE
STORED AS SEQUENCEFILE
STORED AS ORC
STORED AS PARQUET
STORED AS AVRO
STORED AS RCFILE

数据模型

Hive提供了多种数据模型(表类型),以满足不同的数据存储和处理需求。主要的表类型包括:内部表(Managed Table)、外部表(External Table)、分区表(Partitioned Table)和桶表(Bucketed Table)。

内部表

定义:内部表是Hive默认的表类型。当创建内部表时,Hive会将数据移动到Hive的默认存储位置(通常是HDFS的某个目录)。

特点:

  • 数据存储在Hive的默认目录下(例如/user/hive/warehouse)
  • 删除表时,表的元数据和数据都会被删除
  • 适合存储完全由Hive管理的数据

使用场景:适用于数据完全由Hive管理,且不需要与其他系统共享数据的场景。

1
2
3
4
CREATE TABLE managed_table (
id INT,
name STRING
) STORED AS TEXTFILE;

外部表

定义:外部表允许Hive引用存储在其他位置的数据(例如HDFS的其他目录或外部存储系统)。创建外部表时,Hive不会移动数据,而是直接引用数据所在的路径。

特点:

  • 数据存储在指定的外部路径中
  • 删除表时,仅删除表的元数据,数据不会被删除
  • 适合与其他系统共享数据

使用场景:适用于数据需要与其他系统共享,或者数据由其他工具生成的场景。

1
2
3
4
5
CREATE EXTERNAL TABLE external_table (
id INT,
name STRING
)
LOCATION '/path/to/external/data';

分区表

定义:分区表是一种特殊的表,数据按照某些分区键(Partition Key)进行划分。分区键可以是日期、地区等字段。

特点:

  • 数据按分区键存储在不同的目录中,便于查询优化
  • 查询时可以通过分区键过滤数据,提高查询效率
  • 适合处理大规模数据集,尤其是数据按时间或类别划分的场景

使用场景:适用于数据量大且需要按时间或类别快速查询的场景。

1
2
3
4
5
CREATE TABLE partitioned_table (
id INT,
name STRING
)
PARTITIONED BY (year INT, month INT);

桶表

定义:桶表是一种将数据进一步细分的表类型。数据根据某个字段的哈希值被分配到不同的桶(Bucket)中。

特点:

  • 数据在每个分区中被进一步细分为多个桶
  • 适合进行高效的采样和分布式处理
  • 查询时可以通过桶键进行优化,提高查询效率

使用场景:适用于需要对数据进行高效采样或分布式处理的场景。

1
2
3
4
5
6
CREATE TABLE bucketed_table (
id INT,
name STRING
)
PARTITIONED BY (year INT)
CLUSTERED BY (id) INTO 4 BUCKETS;

参考

Hive SQL的编译过程