Hive进阶篇(三)创建表+表结构*(字段类型、文件格式、行格式、分区表)
一、创建表
外部表的彻底删除参考:https://www.cnblogs.com/liuxinrong/articles/14409076.html
二、字段类型
1、简单的
2、复杂的
三、文件格式
1、文本
log(日志文件)、csv文件(逗号分隔的)、tsv(tab分隔的)
2、JSON(一行是一个JSON)
3、Binary(二进制格式的)效率较高
行式的(SequenceFile-用的很少了)、
列式的(使用最广泛,Parquet(用的更多)、ORC)
PARQUET举例--将TXT表转换为PARQUET表:
(1)先建表结构
DROP TABLE IF EXISTS pq_access_logs; CREATE TABLE pq_access_logs ( ip STRING, request_time STRING, method STRING, url STRING, http_version STRING, code1 STRING, code2 STRING, dash STRING, user_agent STRING, `timestamp` int) STORED AS PARQUET;
(2)再将TXT表中的数据加载到建好的表中
INSERT OVERWRITE TABLE pq_access_logs SELECT ip, from_unixtime(unix_timestamp(request_time, 'dd/MMM/yyyy:HH:mm:ss z'), 'yyyy-MM-dd HH:mm:ss z'), method, url, http_version, code1, code2, dash, user_agent, unix_timestamp(request_time, 'dd/MMM/yyyy:HH:mm:ss z') FROM original_access_logs;
这里使用 from_unixtime 和 unix_timestamp函数将日/月/年的顺序进行调整 变成年-月-日的形式。
Parquet-二进制存储的查询效率更高
三、行格式(Row Format)
1、标准分隔符
DELIMETED-反序列化(前面有DE表反)
2、需要自定义序列化类来处理
SERDE-序列化
四、分区表
1、按照日期进行分区
CREATE TABLE partitioned_access_log ( ip STRING,
) ...
PARTITIONED BY (request_date STRING) ...;
hdfs:///access_logs/ ...
— 2017_01_20
— 2017_01_21
— 2017_01_22 ...
— "today"
2、.../年/月/日 式的分区
CREATE TABLE partitioned_access_log ( ip STRING,
) ...
PARTITIONED BY (year STRING, month STRING, day STRING) ...;
hdfs:///access_logs/ ...
— 2017
—— 01
——— 20
——— 21
——— 22 ...
3、分区表的作用
避免全表扫描
提升查询性能 减少IO
方便数据按分区写入(覆盖)
方便管理
4、分区表的操作演示
1)创建分区表-PARTITIONED BY
DROP TABLE IF EXISTS partitioned_access_logs; CREATE EXTERNAL TABLE partitioned_access_logs ( ip STRING, request_time STRING, method STRING, url STRING, http_version STRING, code1 STRING, code2 STRING, dash STRING, user_agent STRING, `timestamp` int) PARTITIONED BY (request_date STRING) STORED AS PARQUET ;
STORED AS PARQUET --文件格式是列式的。
2)将日志表写入分区表,使用动态分区插入
set hive.exec.dynamic.partition.mode=nonstrict; INSERT OVERWRITE TABLE partitioned_access_logs PARTITION (request_date) SELECT ip, request_time, method, url, http_version, code1, code2, dash, user_agent, `timestamp`, to_date(request_time) as request_date FROM pq_access_logs ;
解释:
set hive.exec.dynamic.partition.mode=nonstrict; 是在设置环境变量,
nonstrict是将分区设置成不严格的(默认是严格的-strict),这样就能开启动态分区的插入模式了。
to_date(request_time)是将 年月日时分秒 转换成 日期的格式了。
如果是静态的话,可以看下面这个例子:
set hive.exec.dynamic.partition.mode=nonstrict; INSERT OVERWRITE TABLE partitioned_access_logs PARTITION (request_date = '2020-08-10') SELECT ip, request_time, method, url, http_version, code1, code2, dash, user_agent, `timestamp`, to_date(request_time) as request_date FROM pq_access_logs where request_time >= '2020-08-10' and requset_time < '2020-08-11' ;
将2020年8月10号-2020年8月11号之间的数据全部插入到2020-08-10的分区中。
当然因为一年有365天左右,这样静态的话就得写好多遍这段demo了,所以还是采用动态的更高效。
当然,动态分区和静态分区也是可以混用的-混合分区:
set hive.exec.dynamic.partition.mode=nonstrict; INSERT OVERWRITE TABLE partitioned_access_logs PARTITION (year = '2020', month = '06', day) SELECT ip, request_time, method, url, http_version, code1, code2, dash, user_agent, `timestamp`, to_date(request_time) as request_date FROM pq_access_logs ;
3)查看分区表的分区情况
- show partitions + 分区表表名
(直接通过元数据进行查询,效率最高。有的时候分区多的话,结果的时间会是无序的了)
- 还有一种是select distinct + 分区根据的属性名 + from + 分区表表名
(需要从HDFS将文件读一遍才可得到结果,较慢)
0: jdbc:hive2://localhost:10000> show partitions partitioned_access_logs;
结果:
+--------------------------+--+
| partition |
+--------------------------+--+
| request_date=2014-06-14 |
| request_date=2014-06-15 |
+--------------------------+--+
2 rows selected (0.277 seconds)
有两个分区创建出来了-两天的日志信息
4)看分区表的目录形式
[root@cdh alternatives]# hdfs dfs -ls /user/hive/warehouse/partitioned_access_logs/
Found 2 items
drwxrwxrwt - hive hive 0 2021-02-17 14:55 /user/hive/warehouse/partitioned_access_logs/request_date=2014-06-14
drwxrwxrwt - hive hive 0 2021-02-17 14:55 /user/hive/warehouse/partitioned_access_logs/request_date=2014-06-15
可以看到该分区表的各分区之间是并列的形式
Hive的分区目录名结尾是一种key(分区字段)=value(日期)的形式,不仅仅只有日期
每个分区目录下面存的就是分区内的结果文件,文件的命名会以编号的形式按顺序拍好.
5) 分区表加字段
alter table + 分区表名 + add columns (要增加的分区字段名 + 数据类型);
下面的写法也可以:
alter table + 分区表名(也可以是数据库.表名的形式) + add + partition (分区字段名 = '指定的分区名中的日期')
注:分区表新加入的字段并不能真正插入数据,
因为老的分区结构是在表结构刚建好之后就保存在元数据中的,是不会因为新字段的加入就改变的.
如果要增加分区并且真正地可以插入数据的话,
- 对于内部表:就需要删除分区表,然后再创建一个新的分区表. 因为删除个别分区之后里面的数据也会被删除.
- 对于外部表:可先删除掉新加的分区字段所在的分区(删掉的仅仅是表结构),再将其重建即可显示出来了.
6) 读取个别分区
select * from + 分区表的表名+ where + 分区字段名 = '指定的分区名中的日期'
也可以在后面加上 limit+行数 进行打印行数的限制
7) 删除个别分区字段
alter table + 分区表名(也可以是数据库.表名的形式) + drop + partition (分区字段名 = '指定的分区名中的日期')
五、Storage Handler
通过创建一个外部表 Create External Table to Export Data
将数据导入到不同的数据库中 像:
1.HBase
2.ElasticSearch