一、hive简介
Hive是由Facebook开源,基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
例如统计类需求,
(1)在hadoop体系下我们用MapReduce程序实现的,当需要些Mapper、Reducer和Driver三个类,并实现对应逻辑,相对频繁。
(2)在通过Hive SQL实现时,只需要一行就能实现,简单方便;例如:
select sum(power)from testTable group by mac;
二、Hive本质
Hive是一个Hadoop客户端,用于将HQL转化成MapReuce程序。
(1)hive的每张表的数据存储在HDFS
(2)hive分析数据底层的实现是MapReduce(也可以是Spark或者Tez)
(3)执行程序运行在yarn上
三、Hive架构原理
四、Hive的安装与元数据配置
1.下载地址:
2.安装步骤:
(1)将apache-hive-3.1.3-bin.tar.gz上传到 Linux 服务器
(2)解压压缩包到指定的目录(自定义目录)
(3)添加环境变量到profile中;刷新配置文件
#HIVE_HOME
export HIVE_HOME=/{自定义的目录}
export PATH=$PATH:$HIVE_HOME/bin
(4)在mysql创建元数据库 metastore
(5)在$HIVE_HOME/conf目录汇总新建hive-site.xml文件,并添加以下配置
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- jdbc连接的URL -->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop102:3306/metastore?useSSL=false</value>
</property>
<!-- jdbc连接的Driver-->
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<!-- jdbc连接的username-->
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>
<!-- jdbc连接的password -->
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>123456</value>
</property>
<!-- hive元数据存储版本的校验-->
<property>
<name>hive.metastore.schema.verification</name>
<value>false</value>
</property>
<!--元数据存储授权-->
<property>
<name>hive.metastore.event.db.notification.api.auth</name>
<value>false</value>
</property>
<!-- Hive默认在HDFS的工作目录 -->
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
</configuration>
(6)bin目录下执行改脚本,初始化元数据库
bin/schematool -dbType mysql -initSchema -verbose
3.验证元数据是否配置成功
(1)启动hive
cd $HIVE_HOME
bin/hive
(2)使用hive
show databases;
show tables;
create table test (id int,name string);
insert into test values(1,"ss");
select * from test;
(3)重新开启一个窗口,启动hive;若两个窗口同时都可以操作hive,都没有出现异常则说明配置成功
五、Hive服务部署
hive的hiveserver2服务的作用是提供jdbc/odbc接口,为用户提供远程访问hive数据功能
1.hiveserver2部署
1)hadoop端配置:
修改core-site.xml
cd $HADOOP_HOME/etc/hadoop
vim core-site.xml
添加如下配置:
<!--配置所有节点的用户都可作为代理用户-->
<property>
<name>hadoop.proxyuser.xxx.hosts</name>
<value>*</value>
</property>
<!--配置用户能够代理的用户组为任意组-->
<property>
<name>hadoop.proxyuser.xxx.groups</name>
<value>*</value>
</property>
<!--配置用户能够代理的用户为任意用户-->
<property>
<name>hadoop.proxyuser.xxx.users</name>
<value>*</value>
</property>
2)Hive端配置:
在hive-site.xml中添加如下配置信息
vim hive-site.xml
<!-- 指定hiveserver2连接的host -->
<property>
<name>hive.server2.thrift.bind.host</name>
<value>hadoop102</value>
</property>
<!-- 指定hiveserver2连接的端口号 -->
<property>
<name>hive.server2.thrift.port</name>
<value>10000</value>
</property>
3)测试
(1)启动hiveserver2
bin/hive --service hiveserver2
(2)使用命令行客户端beeline进行远程访问
启动beeline
bin/beeline -u jdbc:hive2://hadoop102:10000 -n xxx
看到如下信息
Connecting to jdbc:hive2://hadoop102:10000
Connected to: Apache Hive (version 3.1.3)
Driver: Hive JDBC (version 3.1.3)
Transaction isolation: TRANSACTION_REPEATABLE_READ
Beeline version 3.1.3 by Apache Hive
0: jdbc:hive2://hadoop:10000>
2.metastore部署
独立部署模式:
首先保证metastore服务的配置文件 hive-site.xml包含连接元数据库所需的参数:
<!-- jdbc连接的URL -->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop:3306/metastore?useSSL=false</value>
</property>
<!-- jdbc连接的Driver-->
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<!-- jdbc连接的username-->
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>
<!-- jdbc连接的password -->
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>123456</value>
</property>
其次保证hiveserver2和每个hive cli的配置文件hive-site.xml中包含访问metastore服务所需的以下参数:
<property>
<name>hive.metastore.uris</name>
<value>thrift://hadoop:9083</value>
</property>
主机名需要改为metastore服务所在节点,端口号无需修改
测试:
启动metastore
hive --service metastore
重新启动客户端 并执行查询语句 若访问整张说明配置成功
六、Hive使用技巧
1.hive常用交互命令
1)表创建,并插入一条数据
hive (default)> create table test(id int,mac string);
OK
Time taken: 1.291 seconds
hive (default)> insert into table test values(1,"123");
hive (default)> select * from test;
OK
test.id test.mac
1 123
Time taken: 0.144 seconds, Fetched: 1 row(s)
2)“-e”不进入hive的交互窗口执行hql语句
bin/hive -e "select id from test;"
3)“-f”执行脚本中的hql语句
(1)在/opt/module/hive/下创建datas目录并在datas目录下创建hivef.sql文件
bin/hive -f /opt/module/hive-3.1.3/datas/hivef.sql
bin/hive -f /opt/module/hive-3.1.3/datas/hivef.sql > /opt/module/hive-3.1.3/datas/hivef_result.txt
2.hive参数配置
1)查看当前所有的配置信息
hive (default)> set;
2)参数配置的是三种方式
(1)配置文件方式
默认配置文件:hive-default.xml
自定义配置文件:hive-site.xml
注意事项:用户自定义的配置会覆盖默认配置,另外hive作为hadoop的客户端启动,hive的配置也会覆盖hadoop的配置。配置文件的设定对本机的所有hive进程都有效
(2)命令行参数方式
(2.1)启动hive时,可以在命令行添加 -hiveconf param=value来设定参数。例如:
bin/hive -hiveconf mapreduce.job.reduces=10;
需要注意的是该种方式仅对本次hive启动有效
(2.2)查看参数设置
hive (default)> set mapreduce.job.reduces;
(3)参数声明方式
可以在HQL中使用SET关键字设定参数,例如:
hive(default)> set mapreduce.job.reduces=10;
需要注意的是该种方式仅对本次hive启动有效
3.hive常见属性配置
1)hive客户端显示当前库和表头
(1)在hive-site.xml中加入如下两个配置:
<property>
<name>hive.cli.print.header</name>
<value>true</value>
<description>Whether to print the names of the columns in query output.</description>
</property>
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
<description>Whether to include the current database in the Hive prompt.</description>
</property>
(2)Hive客户端在运行时可以显示当前使用的库和表头信息
hive (default)> select * from test;
OK
test.id test.mac
1 123
Time taken: 0.144 seconds, Fetched: 1 row(s)
2)Hive运行日志路径配置
(1)Hive的log默认存放在/tmp/user/hive.log目录下
(2)修改Hive的log存放日志到/opt/module/hive/logs
(2.1)修改$HIVE_HOME/conf/hive-log4j2.properties.template文件名称为hive-log4j2.properties
mv hive-log4j2.properties.template hive-log4j2.properties
(2.2)在hive-log4j2.properties文件中修改log存放位置
vim hive-log4j2.properties
修改配置如下:
property.hive.log.dir=/opt/module/hive/logs
3)hive的jvm堆内存设置
新版本的hive启动时,默认申请的jvm堆内存大小为256M,jvm对内吨申请的太小了,导致后期开启本地模式,执行复杂的sql时经常会报错:java.lang.OutOfMemoryError: Java heap space,因此最好提前调整一HADOOP_HEAPSIZE这个参数。
(1)修改$HIVE_HOME/conf下的hive-env.sh.template为hive-env.sh
pwd
/opt/module/hive/conf
mv hive-env.sh.template hive-env.sh
(2)将hive-env.sh其中的参数export HADOOP_HEAPSIZE改为2048,重启Hive
# The heap size of the jvm stared by hive shell script can be controlled via:
export HADOOP_HEAPSIZE=2048
4)关闭hadoop虚拟内存检测
在yarn-site.xml中关闭虚拟内存检查(虚拟内存校验,如果已经关闭了,就不需要配了)
(1)修改前先停hadoop
pwd
/opt/module/hadoop-3.1.3/etc/hadoop
vim yarn-site.xml
(2)添加如下配置
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
(3)修改完记得分发yarn-site.xml,并重启yarn
七、DDL数据定义
1.数据库
1)创建数据库语法
CREATE DATABASE [IF NOT EXISTS] database_name
示例
-- 创建数据库,不指定路径; 不指定路径时,其默认路径为${hive.metastore.warehouse.dir}/database_name.db
create database db_hive1;
-- 创建一个数据库,指定路径
create database db_hive2 location '/db_hive2';
-- 创建一个数据库,带有dbproperties
create database db_hive3 with dbproperties('create_date'='2022-11-18');
1)查询数据库
展示所有数据库
SHOW DATABASES [LIKE 'identifier_with_wildcards'];
注:like通配表达式说明:*表示任意个任意字符,|表示或的关系。
查看数据库信息
DESCRIBE DATABASE [EXTENDED] db_name;
3)修改数据库
用户可以使用alter database命令修改数据库某些信息,其中能够修改的信息包括deproperties,location,owner user。需要注意的是:修改数据库location,不会改变当前已有表的路径信息,而只是改变后续创建的新表的默认父路径
--修改dbproperties
ALTER DATABASE database_name SET DBPROPERTIES (property_name=property_value, ...);
--修改location
ALTER DATABASE database_name SET LOCATION hdfs_path;
--修改owner user
ALTER DATABASE database_name SET OWNER USER user_name;
4)删除数据库
语法
DROP DATABASE [IF EXISTS] database_name [RESTRICT|CASCADE];
-- RESTRICT:严格模式,若数据库不为空,则会删除失败,默认为该模式。
-- CASCADE:级联模式,若数据库不为空,则会将库中的表一并删除。
5)切换数据库
USE database_name;
2.表
1)创建表
(1)普通建表
(1.1)完整语法
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]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]
[TBLPROPERTIES (property_name=property_value, ...)]
(1.2)关键字说明
- TEMPORARY
临时表,该表只在当前会话可见,会话结束,表会被删除。
- EXTERNAL
外部表,与之相对应的是内部表(管理表)。管理表意味着Hive会完全接管该表,包括元数据和HDFS中的数据。而外部表则意味着Hive只接管元数据,而不完全接管HDFS中的数据。
- data_type
Hive中的字段类型可分为基本数据类型和复杂数据类型。
基本数据类型如下:
| Hive | 说明 | 定义 |
|---|---|---|
| tinyint | 1byte有符号整数 | |
| smallint | 2byte有符号整数 | |
| int | 4byte有符号整数 | |
| bigint | 8byte有符号整数 | |
| boolean | 布尔类型,true或者false | |
| float | 单精度浮点数 | |
| double | 双精度浮点数 | |
| decimal | 十进制精准数字类型 | decimal(16,2) |
| varchar | 字符序列,需指定最大长度,最大长度的范围是[1,65535] | varchar(32) |
| string | 字符串,无需指定最大长度 | |
| timestamp | 时间类型 | |
| binary | 二进制数据 |
复杂数据类型如下;
| 类型 | 说明 | 定义 | 取值 |
|---|---|---|---|
| array | 数组是一组相同类型的值的集合 | array | arr[0] |
| map | map是一组相同类型的键-值对集合 | map<string, int> | map['key'] |
| struct | 结构体由多个属性组成,每个属性都有自己的属性名和数据类型 | struct<id:int, name:string> | struct.id |
注:类型转换
Hive的基本数据类型可以做类型转换,转换的方式包括隐式转换以及显示转换。
方式一:隐式转换
具体规则如下:
a. 任何整数类型都可以隐式地转换为一个范围更广的类型,如tinyint可以转换成int,int可以转换成bigint。
b. 所有整数类型、float和string类型都可以隐式地转换成double。
c. tinyint、smallint、int都可以转换为float。
d. boolean类型不可以转换为任何其它的类型。
详情可参考Hive官方说明:Allowed Implicit Conversions
方式二:显示转换
可以借助cast函数完成显示的类型转换
a.语法
cast(expr as <type>)
b.案例
hive (default)> select '1' + 2, cast('1' as int) + 2;
_c0 _c1
3.0 3
- PARTITIONED BY
创建分区表
- CLUSTERED BY ... SORTED BY...INTO ... BUCKETS(重点)
创建分桶表
- ROW FORMAT
指定SERDE,SERDE是Serializer and Deserializer的简写。Hive使用SERDE序列化和反序列化每行数据。详情可参考 Hive-Serde。语法说明如下:
语法一: DELIMITED关键字表示对文件中的每个字段按照特定分割符进行分割,其会使用默认的SERDE对每行数据进行序列化和反序列化。
ROW FORAMT DELIMITED
[FIELDS TERMINATED BY char]
[COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char]
[LINES TERMINATED BY char]
[NULL DEFINED AS char]
注:
- fields terminated by :列分隔符
- collection items terminated by : map、struct和array中每个元素之间的分隔符
- map keys terminated by :map中的key与value的分隔符
- lines terminated by :行分隔符
语法二: SERDE关键字可用于指定其他内置的SERDE或者用户自定义的SERDE。例如JSON SERDE,可用于处理JSON字符串。
ROW FORMAT SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)]
- STORED AS(重点)
指定文件格式,常用的文件格式有,textfile(默认值),sequence file,orc file、parquet file等等。
- LOCATION
指定表所对应的HDFS路径,若不指定路径,其默认值为
${hive.metastore.warehouse.dir}/db_name.db/table_name
- TBLPROPERTIES
用于配置表的一些KV键值对参数
(2)Create Table As Select(CTAS)建表
该语法允许用户利用select查询语句返回的结果,直接建表,表的结构和查询语句的结构保持一致,且保证包含select查询语句放回的内容
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] table_name
[COMMENT table_comment]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
(3)Create Table Like语法
该语法允许用户复刻一张已经存在的表结构,与上述的CTAS语法不同,该语法创建出来的表中不包含数据。
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
[LIKE exist_table_name]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
(4)内部表
Hive中默认创建的表都是的内部表,有时也被称为管理表。对于内部表,Hive会完全管理表的元数据和数据文件。
(5)外部表
外部表通常可用于处理其他工具上传的数据文件,对于外部表,Hive只负责管理元数据,不负责管理HDFS中的数据文件。
2)查看表
(1)展示所有表
SHOW TABLES [IN database_name] LIKE ['identifier_with_wildcards']
like通配表达式说明:*表示任意个任意字符,|表示或的关系。
(2)查看表信息
DESCRIBE [EXTENDED | FORMATTED] [db_name.]table_name
-- EXTENDED:展示详细信息
-- FORMATTED:对详细信息进行格式化的展示
3)修改表
(1)重命名表
ALTER TABLE table_name RENAME TO new_table_name
(2)修改列信息
(2.1)增加列
增加新的列,新增列的位置位于末尾。
ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], ...)
(2.2)更新列
修改指定列的列名、数据类型、注释信息以及在表中的位置
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]
(2.3)替换列
用新的列集替换表中原有的全部列
ALTER TABLE table_name REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
4)删除表
DROP TABLE [IF EXISTS] table_name;
5)清空表
TRUNCATE [TABLE] table_name
truncate只能清空管理表,不能删除外部表中数据。
八、DML操作
1.Load
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)];
关键字说明:
(1)local:表示从本地加载数据到Hive表;否则从HDFS加载数据到Hive表。
(2)overwrite:表示覆盖表中已有数据,否则表示追加。
(3)partition:表示上传到指定分区,若目标是分区表,需指定分区
2.Insert
(1)将查询结果插入表中
INSERT (INTO | OVERWRITE) TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement;
关键字说明:
- INTO:将结果追加到目标表
- OVERWRITE:用结果覆盖原有数据
(2)将给定Values插入表中
INSERT (INTO | OVERWRITE) TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...]
(3)将查询结果写入目标路径
INSERT OVERWRITE [LOCAL] DIRECTORY directory
[ROW FORMAT row_format] [STORED AS file_format] select_statement;
3.Export&import
Export导出语句可将表的数据和元数据信息一并到处的HDFS路径,Import可将Export导出的内容导入Hive,表的数据和元数据信息都会恢复。Export和Import可用于两个Hive实例之间的数据迁移。
--导出
EXPORT TABLE tablename TO 'export_target_path'
--导入
IMPORT [EXTERNAL] TABLE new_or_original_tablename FROM 'source_path' [LOCATION 'import_target_path']
九、查询
基本语法
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference -- 从什么表查
[WHERE where_condition] -- 过滤
[GROUP BY col_list] -- 分组查询
[HAVING col_list] -- 分组后过滤
[ORDER BY col_list] -- 排序
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number] -- 限制输出的行数
十、分区表
1.分区表
Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区,这样的查询效率会提高很多。
create table dept_partition
(
deptno int, --部门编号
dname string, --部门名称
loc string --部门位置
)
partitioned by (day string)
row format delimited fields terminated by '\t';
2.分区表读写数据
1)写数据
(1)load
数据准备
在/opt/module/hive/datas/路径上创建文件dept_20220401.log,并输入如下内容。
vim dept_20240101.log
10 行政部 1700
20 财务部 1800
装载数据
load data local inpath '/opt/module/hive/datas/dept_20240101.log'
into table dept_partition
partition(day='20240101') ;
(2)insert
将day='20240101' 分区的数据插入到day='20240102' 分区,可执行如下装载语句
insert overwrite table dept_partition partition (day = '20240102')
select deptno, dname, loc
from dept_partition
where day = '2024-01-01';
2)读数据
查询分区表数据时,可以将分区字段看作表的伪列,可像使用其他字段一样使用分区字段。
select deptno, dname, loc ,day
from dept_partition
where day = '2024-01-01';
3)分区表基本操作
(1)查看所有分区信息
show partitions dept_partition;
(2)增加分区
(2.1)创建单个分区
alter table dept_partition
add partition(day='20240103');
(2.2)同时创建多个分区(分区之间不能有逗号)
alter table dept_partition
add partition(day='20240104') partition(day='20240105');
(3)删除分区
(3.1)删除单个分区
hive (default)>
alter table dept_partition
drop partition (day='20240103');
(3.2)同时删除多个分区(分区之间必须有逗号)
hive (default)>
alter table dept_partition
drop partition (day='20240104'), partition(day='20240105');
(4)修复分区
Hive将分区表的所有分区信息都保存在了元数据中,只有元数据与HDFS上的分区路径一致时,分区表才能正常读写数据。若用户手动创建/删除分区路径,Hive都是感知不到的,这样就会导致Hive的元数据和HDFS的分区路径不一致。再比如,若分区表为外部表,用户执行drop partition命令后,分区元数据会被删除,而HDFS的分区路径不会被删除,同样会导致Hive的元数据和HDFS的分区路径不一致。
若出现元数据和HDFS路径不一致的情况,可通过如下几种手段进行修复。
(4.1)add partition
若手动创建HDFS的分区路径,Hive无法识别,可通过add partition命令增加分区元数据信息,从而使元数据和分区路径保持一致。
(4.2)drop partition
若手动删除HDFS的分区路径,Hive无法识别,可通过drop partition命令删除分区元数据信息,从而使元数据和分区路径保持一致。
(4.3)msck
若分区元数据和HDFS的分区路径不一致,还可使用msck命令进行修复,以下是该命令的用法说明。
hive (default)>
msck repair table table_name [add/drop/sync partitions];
说明:
msck repair table table_name add partitions:该命令会增加HDFS路径存在但元数据缺失的分区信息。
msck repair table table_name drop partitions:该命令会删除HDFS路径已经删除但元数据仍然存在的分区信息。
msck repair table table_name sync partitions:该命令会同步HDFS路径和元数据分区信息,相当于同时执行上述的两个命令。
msck repair table table_name:等价于msck repair table table_name add partitions命令。
3.动态分区
动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。
1)动态分区相关参数
(1)动态分区功能总 开关 (默认true,开启)
set hive.exec.dynamic.partition=true
(2)严格模式和非严格模式
动态分区的模式,默认strict(严格模式),要求必须指定至少一个分区为静态分区,nonstrict(非严格模式)允许所有的分区字段都使用动态分区。
set hive.exec.dynamic.partition.mode=nonstrict
(3)一条insert语句可同时创建的最大的分区个数,默认为 1000 。
set hive.exec.max.dynamic.partitions=1000
(4)单个Mapper或者Reducer可同时创建的最大的分区个数,默认为100。
set hive.exec.max.dynamic.partitions.pernode=100
(5)一条insert语句可以创建的最大的文件个数,默认100000。
hive.exec.max.created.files=100000
(6)当查询结果为空时且进行动态分区时,是否抛出异常,默认false。
hive.error.on.empty.partition=false
十一、分桶表
1.建表语句
create table stu_buck(
id int,
name string
)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
十二、文件压缩格式
1.hadoop压缩概述
| 压缩格式 | 算法 | 文件扩展名 | 是否可切分 |
|---|---|---|---|
| DEFLATE | DEFLATE | .deflate | 否 |
| Gzip | DEFLATE | .gz | 否 |
| bzip2 | bzip2 | .bz2 | 是 |
| LZO | LZO | .lzo | 是 |
| Snappy | Snappy | .snappy | 否 |
为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下表所示:
Hadoop查看支持压缩的方式hadoop checknative。
Hadoop在driver端设置压缩。
| 压缩格式 | 对应的编码/ 解码器 |
|---|---|
| DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
| gzip | org.apache.hadoop.io.compress.GzipCodec |
| bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
| LZO | com.hadoop.compression.lzo.LzopCodec |
| Snappy | org.apache.hadoop.io.compress.SnappyCodec |
压缩性能的比较:
| 压缩 算法 | 原始文件大小 | 压缩文件大小 | 压缩速度 | 解压速度 |
|---|---|---|---|---|
| gzip | 8.3GB | 1.8GB | 17.5MB/s | 58MB/s |
| bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
| LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
2.Hive文件格式
为Hive表中的数据选择一个合适的文件格式,对提高查询性能的提高是十分有益的。Hive表数据的存储格式,可以选择text file、orc、parquet、sequence file等。
1)Text File
文本文件是Hive默认使用的文件格式,文本文件中的一行内容,就对应Hive表中的一行记录。
可通过以下建表语句指定文件格式为文本文件:
create table textfile_table
(column_specs)
stored as textfile;
2)ORC
(1)文件格式
ORC(Optimized Row Columnar)file format是Hive 0.11版里引入的一种列式存储的文件格式。ORC文件能够提高Hive读写数据和处理数据的性能。
与列式存储相对的是行式存储,下图是两者的对比:
如图所示左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
(1.1)行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
(1.2)列存储的特点
因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。
前文提到的text file和sequence file都是基于行存储的,orc和parquet是基于列式存储的。
每个Orc文件由Header、Body和Tail三部分组成。
其中Header内容为ORC,用于表示文件类型。
Body由1个或多个stripe组成,每个stripe一般为HDFS的块大小,每一个stripe包含多条记录,这些记录按照列进行独立存储,每个stripe里有三部分组成,分别是Index Data,Row Data,Stripe Footer。
Index Data: 一个轻量级的index,默认是为各列每隔1W行做一个索引。每个索引会记录第n万行的位置,和最近一万行的最大值和最小值等信息。
Row Data: 存的是具体的数据,按列进行存储,并对每个列进行编码,分成多个Stream来存储。
Stripe Footer: 存放的是各个Stream的位置以及各column的编码信息。
Tail由File Footer和PostScript组成。File Footer中保存了各Stripe的其实位置、索引长度、数据长度等信息,各Column的统计信息等;PostScript记录了整个文件的压缩类型以及File Footer的长度信息等。
在读取ORC文件时,会先从最后一个字节读取PostScript长度,进而读取到PostScript,从里面解析到File Footer长度,进而读取FileFooter,从中解析到各个Stripe信息,再读各个Stripe,即从后往前读。
(1.3)建表语句
create table orc_table
(column_specs)
stored as orc
tblproperties (property_name=property_value, ...);
ORC文件格式支持的参数如下:
暂时无法在iHaier文档外展示此内容
3)Parquet
Parquet文件是Hadoop生态中的一个通用的文件格式,它也是一个列式存储的文件格式。
Parquet文件的首尾都是该文件的Magic Code,用于校验它是否是一个Parquet文件。
首尾中间由若干个Row Group和一个Footer(File Meta Data)组成。
每个Row Group包含多个Column Chunk,每个Column Chunk包含多个Page。以下是Row Group、Column Chunk和Page三个概念的说明:
行组(Row Group): 一个行组对应逻辑表中的若干行。
列块(Column Chunk): 一个行组中的一列保存在一个列块中。
页(Page): 一个列块的数据会划分为若干个页。
Footer(File Meta Data)中存储了每个行组(Row Group)中的每个列快(Column Chunk)的元数据信息,元数据信息包含了该列的数据类型、该列的编码方式、该类的Data Page位置等信息。
(3.1)建表语句
Create table parquet_table
(column_specs)
stored as parquet
tblproperties (property_name=property_value, ...);
支持的参数如下:
暂时无法在iHaier文档外展示此内容
4)压缩
在Hive表中和计算过程中,保持数据的压缩,对磁盘空间的有效利用和提高查询性能都是十分有益的。
(1) Hive 表数据进行压缩
在Hive中,不同文件类型的表,声明数据压缩的方式是不同的。
(1.1)TextFile
若一张表的文件类型为TextFile,若需要对该表中的数据进行压缩,多数情况下,无需在建表语句做出声明。直接将压缩后的文件导入到该表即可,Hive在查询表中数据时,可自动识别其压缩格式,进行解压。
需要注意的是,在执行往表中导入数据的SQL语句时,用户需设置以下参数,来保证写入表中的数据是被压缩的。
--SQL语句的最终输出结果是否压缩
set hive.exec.compress.output=true;
--输出结果的压缩格式(以下示例为snappy)
set mapreduce.output.fileoutputformat.compress.codec =org.apache.hadoop.io.compress.SnappyCodec;
(1.2)ORC
若一张表的文件类型为ORC,若需要对该表数据进行压缩,需在建表语句中声明压缩格式如下:
create table orc_table
(column_specs)
stored as orc
tblproperties ("orc.compress"="snappy");
(1.3) Parquet
若一张表的文件类型为Parquet,若需要对该表数据进行压缩,需在建表语句中声明压缩格式如下:
create table orc_table
(column_specs)
stored as parquet
tblproperties ("parquet.compression"="snappy");
(2)计算过程中使用压缩
(2.1)单个 MR 的中间结果进行压缩
单个MR的中间结果是指Mapper输出的数据,对其进行压缩可降低shuffle阶段的网络IO,可通过以下参数进行配置:
--开启MapReduce中间数据压缩功能
set mapreduce.map.output.compress=true;
--设置MapReduce中间数据数据的压缩方式(以下示例为snappy)
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
(2.2)单条 SQL 语句的中间结果进行压缩
单条SQL语句的中间结果是指,两个MR(一条SQL语句可能需要通过MR进行计算)之间的临时数据,可通过以下参数进行配置:
--是否对两个MR之间的临时数据进行压缩
set hive.exec.compress.intermediate=true;
--压缩格式(以下示例为snappy)
set hive.intermediate.compression.codec= org.apache.hadoop.io.compress.SnappyCodec;