tinyint 1byte
smallint 2byte
int 4byte
bigint 8byte
boolean boolean
float 4byte
double 8byte
string 变长
timestamp
binary
array 定义 xx: array 数据 xx: a_b
map 定义 xx:map 数据 xx: a:'a'_b:1
struct 定义 xx:struct 数据 xx: A_B
通过hive insert数据, hive会通过mapreduce将sql中的数据集转为文件存储到HDFS中。
这个过程由于调用了mapreduce,会变的非常慢。
所以通常的做法是用户自己直接通过HDFS将文件上传上去。
然后再通过hive定义表结构时,同时定义文件中数据的分隔符。
让hive去匹配目标数据。
#表结构定义
create table test3(
name string,
friends array,
children map,
address struct
)
#分隔符定义
row format delimited fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';
# 数据
roy,bob_john,yula:6_sophia:17,lugu_changsha
mike,lea_jacky,rita:7_king:20,chao yang_beijing
# 创建库
CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT comment]
# 库对应的HDFS目录,文件名=databse_name.db
[LOCATION hdfs_path]
# 库的附属参数,保存在元数据库中,db_properties表中 通过desc databse extended db_name;可以查看
[WITH DBPROPERTIES (property_name=property_value,...)]
#库的操作
show databses; #库列表
desc databse db_name; #查看库信息
drop databse db_name; #删库
drop databse db_name cascade; #强制删
alert database db_name set dbproperties('xx'='yy'); #修改库属性
# 创建表 EXTERNAL是否是外部表
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
#表字段
[(col_name type [COMMENT comment], ...)]
#表备注
[COMMENT comment]
#维护分区表
[PARTITIONED BY (col_name type [COMMENT comment], ...)]
#下面三个是维护分桶表
[CLUSTERED BY (col_name,...)]
[SORTED BY (col_name [ASC|DESC], ...)]
[INTO num_buckets BUCKETS]
#行的格式,包括分隔符
[ROW FORMAT row_format]
#表文件存储格式,有三种:TESTFILE(文本,最常见),SEQUENCEFILE(二进制序列文件,压缩用),RCFILE(列式存储格式文件)
[STORED AS file_format]
#表对应的hdfs路径
[LOCATION hdfs_path]
#表的额外属性
[TBLPROPERTIES (name=value,...)]
#根据select_statement查询语句的结果建表
[AS select_statement]
创建表时,通过EXTERNAL标志定义,默认都是内部表。
是否外部表是表的一个属性:
内部表 managed table
外部表 external table
内部表与外部表的区分:
内部表进行drop删除表时,同时也会删除hdfs中的数据。
而外部表不会。
内外表的定义目的是为了区分HDFS中的数据是Hive独有的,还是共享的。
因为Hive通常被用来进行数据查询,而不作为数据管理。
#查询表类型
desc formatted table_name;
# TableType: MANAGED_TABLE
#修改表类型
alter table table_name set tblproperties('EXTERNAL'='TRUE');//外部
alter table table_name set tblproperties('EXTERNAL'='FALSE');//内部
分区类似于mysql分表
根据分区字段,建立多个目录
分区字段是独立于普通字段的。
通过载入数据时指定分区,Hive会自动创建分区目录
注:创建表时指定了分区,导入数据时Hive就强制分配分区
load data local inpath '/home/test.txt' into table test partition(dept_id='20')
load data local inpath '/home/test.txt' into table test partition(dept_id='22')
#导入成功后,就会创建表目录 dept_id=20, 以及dept_id=22
动态分区:
Hive允许导入数据时,不指定分区字段值,自动实现分区。
实现原理:Hive会插入导入数据时,通过mapReduce扫描数据,计算出分区值有多少,然后再创建对应目录
这样做会导致导入数据时,增加了mapreduce操作,导入性能会降低很多。
使用动态分区需要开启配置
set hive.exec.dynamic.partition=true
分桶是Hive更细粒度的数据分区机制。
比如:要对id进行hash分区、对2023年度的数据按月分区,在分区表层面就不好进行操作,需要用分桶表进行处理。
#创建分桶表,分桶数为4
CREATE TABLE table_name(id int, name string)
CLUSTERED BY(id) into 4 buckets;
分桶表使用效果
分桶在hdfs层面,是在表目录内,将文件分成多份。
如:分桶数为4,那么将产生000000_0,000001_0,000002_0,000003_0四份,为什么说是4份,因为每一份可以是多个文件,hive将同一份的多个文件视为一个桶的数据。
000000_0,000000_0_copy_1,000000_0_copy_2 这三个文件, 都归类为第一个桶的文件。
分桶表的实际意义
数据分区
文件按桶分组后,对单桶内数据操作,只需要扫描一部分数据,不需要全表扫描,提高性能。
随机抽样
当数据量很大时,可以直接从某一个桶抽取数据,可以满足只想抽取少量具有某个特征的数据的需求,
更进一步,如果每个桶都取一部分,那么最终抽样数据就拥有整体数据的全部特征,数据也会很均匀。
SELECT * FROM table_name tablesample(bucket 1 from out of 4 on id);
分桶数与reduce数, 当设置项mapreduce.job.reduces=-1时,由hive自己控制reduce数量,Hive通常将reduce数量设置为分桶数,每个reduce负责一个桶的数据处理。
实践
实际场景中,并不像关系型数据库那样,先设计表结构,设计数据分区,再导入或创建数据。
Hive通常用来对已存在的数据进行处理。
对现有文件的结构进行分析,推导出分桶字段,分桶数,然后再设计分桶表。
数据管理的常规操作为增删改查。
Hive基本上全部都支持,但Hive的增删改是基于mapReduce操作进行的,mapReduce执行过程中会有大量磁盘IO,对于小数据量效率非常低,即使插入1条数据也需要20+秒。
注:Hive的行级变更update,delete需要修改配置才能支持。
在大数据或数据仓库场景下,数据几乎也不需要变更,只需要导入导出,查询统计即可。
而Hive的核心就是针对这些操作。
普通导入很快,通常会直接写入到hdfs,涉及某些计算或分区分桶时会调用mapReduce处理。
# local 是否本地文件 overwrite 是否覆盖已有数据
load data [local] inpath 'path' [overwrite] into table table_name [partition (col=value,...)]
导出符合目标格式的数据,如导出到mysql,
#导出到本地文件
insert overwrite local directory '/path' select * from table_name;
#格式化导出本地
insert overwrite local directory '/path'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
select * from table_name
#导出到HDFS
insert overwrite directory '/hive/data/test' select * from table_name;
#导出成sql
insert overwrite local directory '/test.sql'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ';\n'
select 'insert into test(name) values("'+name+'")' from table_name;
Hive的查询基本符合sql语法,包括join
[WITH CommonTableExpression (, CommonTableExpression) *]
SELECT [ALL|DISTINCT] select_expr, select_expre, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT [offset,] rows]
Hive除了实现sql语法,还基于sql增加了很多特性
增加了按字符位置匹配,正则匹配
#后缀匹配
select * from test where name like 'A%';
#位置匹配,第二个字符为A
select * from test where name like '_A%';
#正则匹配,包含ABC字母
select * from test where name rlike '[ABC]';
mysql通过order by对查询结果进行排序。
Hive在大数据领域,数据量大,全局排序代价很大。
因为hive的排序最终是mapReduce实现的,参考mapReduce特性, 每个reduce内可以保证排序, 如果要强制全局有序, 就只能使用一个reduce,这样就无法并行计算。
所以分组排序,是mapReduce的特性延伸。
#sort by
#按id进行分组排序,至于分几个组,要看Hive使用了几个reduce,用户可以通过设置固定几个reduce
select * from test sort by id desc;
#districbute by
#在sort的基础上,按字段进行分区排序
#districbute是利用字段hash码与reduce数量取模进行分区的
#select * from test districbute by age sort by id desc;
#cluster by
#等价于 districbute sort同字段, 只能升序
with关键字 Common Table Expression(CTE)
通过with创建临时视图,简化复杂sql
#查询在部门1的所有人
with cte_dept_1 as (select name,deptno from dept where deptno='1')
select * from cte_dept_1;
#查询用户以及部门信息
with cte_dept as (select name,deptno from dept),
cte_user as (select deptno,uname from user)
select e.name as dept_name, e.deptno, e.uname from cte_user e left join cte_dept d on d.deptno=e.deptno;
Hive内置了大量的函数,通过指令show functions; desc function extended nvl;可以详细查看函数介绍和使用示例。
文档:
LanguageManual UDF - Apache Hive - Apache Software Foundation
开窗函数,为每个分析函数(sum等)指定统计数据窗口, 窗口可以调整。
#格式
select sum(x) over(partition by col1) as a1, #按col1分组后进行sum统计
count(y) over(partition by col2 order by col3), #按col2分组并排序后进行count统计
#按col4分组并排序后,取当前行+前一条+后一条3条数据,进行avg统计。
avg(z) over(partition by col4 order by col5 rows between 1 preceding and 1 following)
from test;
rows between 必须在order by后面, 对排序后的结果进行过滤限制。
between后面可以跟 n preceding前n行, n following 后n行,current row当前行, unbounded 不限制
Hive自定义函数有三类:
UDF user defined function
针对单行字段数据处理,输入单个数据, 输出单个数据
UDAF user defined agg function
针对统计数据, 输入一列数据, 输出一个数据
UDTF user defined table generating function
针对生成数据, 输入一个数据,输出一列数据
引入依赖
org.apache.hive
hive-exec
3.1.2
创建函数
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class Test extends UDF{
public Text evaluate(final Text s){
if(s==null)return null;
return new Text(s.toString().toLowerCase());
}
}
为系统引入自定义函数
#引入jar包
add jar /test.jar;
#查看引入的jar包
list jars;
#创建函数
create function test as 'com.example.Test';
#使用
select test(x) from table_name;