内容来自于《大数据Hive离线计算开发实战》
Hive是一个基于Hadoop的数据仓库和分析系统,用于管理和查询大型数据集。以下是Hive的原理:
总的来说,Hive是一个用于大数据处理的工具,其原理是通过将查询语句转换成MapReduce程序来执行,并利用Hadoop和HDFS进行存储和计算。通过这种方式,Hive可以简化复杂的数据挖掘和大数据分析工作,提高系统性能和效率。
对新手来说,你其实可以理解我就是正常操作结构化的数据库,类似于操作MySQL、PostgreSQL等数据库,写普通的SQL语句进行数据查询、分析。那我该篇文章也就是梳理最简单的最全的操作方法,帮助刚上手Hive的程序员快速开始写SQL语句进行查询分析数据。
数据类型 | 长度 |
---|---|
TINYINT | 1byte有符号整数 |
SMALLINT | 2byte有符号整数 |
INT | 4byte有符号整数 |
BIGINT | 8byte有符号整数 |
BOOLEAN | 布尔类型 true 或者 false |
FLOAT | 单精度浮点数 |
DOUBLE | 双精度浮点数 |
STRING | 字符序列,可以指定字符集;可以使用单引号或双引号 |
TIMESTAMP | 整数、浮点数或者字符串 |
BINARY | 字节数组 |
数据类型 | 描述 |
---|---|
STRUCT | 与C语言中的结构 struct类型相似,都可以通过“点”符号访问元素内容。例如,某表中某个列的数据类型为STRUCT(firName STRING,lastName STRING),那么第一个元素可通过字段名.firName来引用 |
MAP | MAP是一个键值对映射集合。例如,表中某个列的数据类型是MAP,存放数据的格式是键:值,通过键就可以获取值 |
ARRAY | ARRAY数组是一组具有相同类型变量的集合,这些变量被称为数组的元素,每个元素度有一个下标编号,编号从0开始 |
create table enterprise.employee(id int,info struct<name:string,age:int>) row format delimited fields terminated by ',' collection items terminated by ':';
数据实例
1,zhangsan:10
2,lisi:20
3,wangwu:30
create table enterprise.employee_1(id int,perf Map<string,int>) row format delimited fields terminated by '\t' collection items terminated by ',' map keys terminated by ':';
数据案例
1 job:80,team:60,person:50
2 job:60,team:70
3 job:80,team:90,person:100
create table enterprise.employee_2(name string,emp_id_list array<int>) row format delimited fields terminated by ',' collection items terminated by ':';
数据案例
zhangsan,1:2:3
lisi,4:5:6
wangwu,7:8:9
hive> create database enterprise;
如果数据库enterprise
已经存在的话,会跑出一个异常。
所以命令可以改为
hive> create database if not exists enterprise;
查看Hive中所包含的所有数据库
hive> show databases;
查询数据库以e开头数据库
hive> show databases like 'e.*'
我们还可以为每个数据库增加描述
hive>create database if not exists enterprise commit '企业信息表';
我们也能查看数据库enterprise
的信息
describe database enterprise;
通过数据库信息可知,在HDFS
文件系统上,enterprise
数据库是以“.db
”结尾,这是Hive
数据仓库的设计,用来标识该目录是数据库目录,同时可以知道父目录是/user/hive/warehouse
,该父目录层级可以在Hive
的配置文件hive-site.xml
中的hive.metastore.warehouse.dir
属性进行配置。
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
//删除数据库
hive> drop database enterprise;
//防止数据库不存在的时候,抛出异常
hive> drop database if exists enterprise;
// Hive自己先删除数据库中的表,然后删除数据库
hive> drop database if exists enterprise cascade;
create table if not exists enterprise.account(acc_name string,acc_balance double) row format delimited fiedls terminated by '\t' location '/user/hive/warehouse/enterprise.db/account';
注意,数据目录总是以“.db
”结尾的,其中enterprise.db
目录下的子目录account
就是表,所以我们说Hive
中的表也是一个表目录。即在HDFS
分布式文件系统上所创建的目录。默认情况下,Hive
总是将创建的表目录放置在这个表所属的数据库目录下。
我们可以列举指定数据库下的表
hive> show tables in enterprise;
管理表也称内部表或临时表,Hive
控制着管理表的整个生命周期,默认情况下Hive
管理表的数据存放在Hive
主目录/usr/hive/datawarehouse/
,并且当我们删除一张表时,这张表的数据也会相应地被删除。我们上述操作建表都是建的是管理表。
Hive中的外部表(External Table
)是一种特殊类型的表,它指向已经在HDFS
中存在的数据。与内部表(Managed Table
)不同,外部表不会移动数据到数据仓库目录中,只是与外部数据建立一个链接。
以下是关于Hive
外部表的一些主要特点:
HDFS
中存在的数据,可以创建Partition
。DML
操作,也不能创建索引。SQL
语句来完成,而不需要先将外部表中的数据装载进数据库中。LOCATION
)。总的来说,Hive
的外部表提供了一种方便的方式来查询和管理已经在HDFS
中存在的数据,同时保持了Hive
表的元数据组织特性。它特别适用于想要在Hive
之外使用表的数据的情况,例如多个部门想使用一个表的数据。
在创建表时,如果加上关键字external
,则创建为外部表。外部表中的数据生命周期不受Hive
的控制,且可以和其他外部表进行数据的共享。
create external table product(pro_name string,pro_price double) row format delimited fields terminated by '\t' location '/data/stocks';
创建表
create table student(name string,age int) row format delimited fields terminated by '\t';
修改表名
alter table student rename to stu
增加字段
alter table stu add columns(sex string,birthday string)
drop table tableName;
随着数据库中数据量不断激增,就不得不考虑数据库存储和计算性能问题。Hive就是使用分区表的结构来解决问题的。
Hive分区的概念与传统关系型数据库表分区不同。传统数据库的表分区方式,就MySQL而言,是指将一张表分解成多个更小的、容易管理的部分。从逻辑上看只有一张表,单底层却是由多个物理分区组成的,每个物理分区中存储真实的数据,在数据插入的时候自动分配分区,这些物理分区可以分布在不同的物理服务器设备上。由于Hive表中的数据实际存储在HDFS上,所以Hive的分区方式是在HDFS文件系统上的一个分区名对应一个目录名,子分区名就是子目录名,并不是一个实际字段。因此可以这样理解,在插入数据的时候指定分区,其实就是新建一个目录或者子目录,并在相应的目录上添加数据文件,实现Hive表分区的功能。
所以概括来说,Hive的分区是创建层级目录的一种方式。
创建一张静态分区表student_partition,单分区列为sex
create table student_partition(name string,age int) partitioned by(sex string) row format delimited fields terminated by '\t';
load数据
load data local inpth '/home/school/student.txt' into table student_partition partition(sex='woman')
创建一张静态分区表student_partition,多分区列为sex、native
create table student_partition_multi(name string,age int) partitioned by(sex string,native string) row format delimited fields terminated by '\t';
load数据
load data local inpth '/home/school/student.txt' into table student_partition_multi partition(sex='man',native='GanSu')
如果在实际开发中经常使用静态分区的话,在插入数据的时候,就必须首先知道有哪些分区类型,针对每一个分区要单独使用load data
命令载入数据。使用Hive的动态分区就可以解决自动将数据分配到各自分区。动态分区和静态分区的区别就是不用指定分区目录,由系统自己选择
开启动态分区功能
set hive.exec.dynamic.partition=true;
//此属性的默认值是strict,意思是不允许分区列全部是动态的。将其值设置为nonstrict,意思是所有的分区都是动态的
set hive.exec.dynamic.partition.mode=nonstrict;
//最大动态分区个数
set hive.exec.max.dynamic.partitions.pernode=1000;
动态分区表
create table student_partition_multi(name string,age int) partitioned by(sex string,native string) row format delimited fields terminated by '\t';
load数据
load data local inpath '/home/school/student.txt' into table student;
写入分区表
insert overwrite table student_partition_multi partition(sex,native) select name,age,sex,native from student;
insert overwrite table sogou.sogou_xj select * from sogou.sogou_500w where keyword like '%仙剑奇侠传%'
create table sogou.sogou_xj_backup as select * from sogou.sogou_xj;
建表
create external table if not exists sogou.sogou_liangjian(ts string,uid string,keyword string,rank int,orders int,url string) row format delimited fields terminated by '\t' stored as textfile location '/sogou/liangjian';
通过HDFS命令行接口直接将liangjian.txt数据导入Hive表,其实就是将数据文件放到LOCATION属性所指向的路径下,然后就可以在Hive中通过HiveQL进行操作查询了。
hadoop fs -put liangjian.txt /sogou/liangjian
hadoop fs -get /user/hive/warehouse/sogou.db/sogou_xj_backup/000000_0
select */field1,field2 from tableName
select count(*) from sogou.sogou_500w where keyword like '%亮剑%'
GROUP BY语句通常会和聚合函数一起使用,其语意为按照一个或者多个列对结果进行分组,然后使用聚合函数对每个组执行聚合运算。
统计搜索过关键词包含“亮剑”一词的用户及关键词搜索频率
select t.uid,t.keyword,count(*) from (select * from sogou.sogou_500w where keyword like '%亮剑%') t group by t.uid,t.keyword
HAVING子句允许用户通过一个简单的语法,来完成原本需要通过子查询才能对GROUP BY语句产生的分组结果进行条件过滤的任务。
统计搜索关键词中包含“亮剑”一词的用户及关键词搜索次数,并且过滤出搜索次数大于30的用户
select t.uid,t.keyword,count(*) as cnt from (select * from sogou.sogou_500w where keyword like '%亮剑%') t group by t.uid,t.keyword having cnt >= 30;
Hive中ORDER BY语句和SQL中的定义是一样的,其会对查询结果集执行一次全局排序,也就是说会有一个所有数据都通过一个reducer进行处理的过程。对于大数据集,这个过程可能会消耗太多的时间。
Hive增加了一个可供选择的方式,那就是SORT BY语句,该语句只会在每个reducer中对数据排序,也就是说会执行一个局部排序,因此可以保证每个reducer的输出数据都是有序的(但并非全局有序),如此就可以提高后面进行全局排序效率。
因此若要在数据量级非常大的情况下排序,可以选择SORT BY语句,平时可以选择ORDER BY语句完成排序任务。
select uid,count(*) as cnt from sogou.sogou_500w group by uid order by cnt desc limit 30;
库表准备
create database if not exists scott;
use scott;
//员工表 emp
create external table emp(empno varchar(50),ename varhcar(30),job varchar(50) mgr varchar(30) sal double,deptno varchar(50)) row format delimited fields terminated by ',' stored as textfile location '/scott/emp'
//部门表 dept
create external table dept(deptno varchar(50),dname varchar(30),loc varchar(30)) row format delimited fields terminated by ',' stored as textfile location '/scott/dept'
Hive的连接分为:内连接、自然连接和外连接
也可以简写为join
,只有进行连接的两个表中都存在于连接标准相匹配的数据才会被保留下来,内连接分为等值连接和不等值连接。
等值连接是指,在使用等号操作符的连接。
查看部门30中的员工,要求显示员工的姓名、职位、所属部门编号以及部门名称。
select emp.ename,emp.job,dept.deptno,dept.dname from emp inner join dept on emp.deptno = dept.deptno where dept.deptno = 30;
不等值连接是指,使用 > 、>=、 <=、 < 、!> 、!< 和<> 操作符的连接。
获取部门编号不等于10的所有员工的姓名、职位以及员工所属的部门名称和部门地理位置信息。
select emp.ename,emp.job,dept.dname,dept.loc from emp innert join dept on emp.deptno = dept.deptno where dept.deptno != 10;
自然连接是在广义笛卡尔积中选出同名属性上符合相等条件的元祖,再进行投影,去掉重复的同名属性,组成新的关系。即自然连接是在两张表中寻找那些数据类型和列名都相同的字段,然后自动将它们连接起来,并返回所有符合条件的结果,它是通过对参与表关系中所有同名的属性对取等(即相等比较)来完成,故无需自己添加连接条件。自然连接和外连接的区别在于,对于无法匹配的记录,外连接会虚拟一条与之匹配的记录来保全连接表中的所有记录,但自然连接不会。
查询部门编号为10和30的所有员工的姓名、职位和部门名称
select ename,job,dname from emp natural join dept where dept.deptno in ('10','30');
外连接分为左外连接查询、右外连接查询和全外连接。
左外连接即以连接中的左表为主,返回左表的所有信息和右表中符合连接条件的信息,对于右表中不符合连接条件的则补空值。
select e.empno,e.ename,e.job,d.deptno,d.dname,d.loc from emp e left outer join dept d on deptno = d.deptno
右外连接即以连接中的右表为主,返回右表的所有信息和左表中符合连接条件的信息,对于左表中不符合连接条件的则补空值。
select e.empno,e.ename,e.job,d.deptno,d.dname,d.loc from emp e right outer join dept d on deptno = d.deptno
全外连接查询结果等于左外连接和右外连接的和
select e.empno,e.ename,e.job,d.deptno,d.dname,d.loc from emp e full outer join dept d on deptno = d.deptno
自连接指连接的表是同一张表,使用自连接可以将自身表的一个镜像当成另一个表来对待,所以自连接适用于表自己喝自己的连接查询。
在员工表emp中我们想查询经理的下属员工有哪些
select e1.empno,e2.empno,e2.ename,e2.job,e2.sal from emp e1,emp e2 where e1.empno = e2.mgr;
查看Hive的内置函数
show functions;
加法“+”
select 10+2;
减法“-”
select 10-2;
乘法“*”
select 10*2;
除法“/”
select 10/2;
round四舍五入函数的应用
select round(88.945,2);
ceil向上取整函数应用
select ceil(88.12);
floor向下取整函数的应用
select floor(88.92);
pow取平方函数的应用
select pow(3,2);
pmod取模函数,即取余数的应用
select pmod(13,3);
lower转小写函数
select lower('AAAAA');
upper转大写函数
select upper('AAAAA');
length字符串长度函数
select length('AAAAA');
concat字符串拼接函数
select concat("hadoo","hive");
substr求子串函数
// 从字符串a中,第3位开始取,取右边所有的字符
sekect substr("hadoop",3);
// 从字符串a中,第b位开始取,取c个字符
sekect substr("hadoop",3,1);
trim去前后空格函数
select trim(" hive ");
get_json_object用于处理json格式数
据的函数
select get_json_object('{"name":"zhangsan","age":12}','$.name')
类型转换函数cast应用
select cast(99 as double);
select cast("2020-01-30" as date);
select year("2019-9-16 17:18:10"),month("2019-9-16 17:18:10"),day("2019-9-16 17:18:10")
to_date返回日期时间字段中的日期部分
select to_date("2019-9-16 17:18:10")
case…when… 是,条件表达式,语法格式为case A when B then C [when D then E]* [else F] end.
对A来说,如果判断为B则返回C,如果判断为D则返回E(此处判断条件可为多个),如果以上都不是则返回F。注意,最后还有一个end结束符。
select ename,job,sal case job wher 'manager' then sal + 2000 when 'clerk' then sal + 1000 else sal + 400 from emp;
count:返回行数
select count(*) from emp;
sum:组内某列求和函数
select sum(sal),job from emp group by job;
min:组内某列最小值
select min(sal),job from emp group by job;
max:组内某列最大值
select max(sal),job from emp group by job;
avg:组内某列平均值
select avg(sal),job from emp group by job;
Hive中的视图和关系型数据库中视图在概念上是一致的,都是一组数据的逻辑表示,享用基本原始表的数据而不会另生成一份数据,是纯粹的逻辑对象。本质上,视图是一条SQL语句的集合,但该条SQL不会立即执行,我们称其为逻辑视图,它没有关联的实际存储。当有查询需要引用视图时,Hive才真正开始将查询中的过滤器推送到视图中去执行。
语法
create view [if not exists] db_name.view_name as select [column_name...] from table_name where ...
创建一个视图,其内容包含表sogou_500w中关键词不为空的前1000条数据
create view sogou_view as select * from sogou_500w where keyword is not null limit 1000;
show tables;
desc sogou_view;
desc formatted sogou_view;
drop view if exists sogou.sogou_view;
Hive分桶表是相对于分区表来说的,分区表它属于一种粗粒度的划分,而分桶表是对数据进行更细粒度的划分。分桶表将整个数据内容按照某列属性值的哈希值进行区分,例如按照用户ID属性分为3个桶,分桶的规则就是对分桶字段值进行取哈希值,然后用该哈希值除以桶的个数取余数,余数决定了该条记录将会被分在哪个桶中。余数相同的记录会被分子啊同一个桶中。需要注意的是,在物理结构上一个桶对应一个文件,而分区表的分区只是一个目录,至于目录下有多少数据是不确定的。
通过clustered by(字段名) into bucket_num buckets 分桶,意思是根据字段名分成多个桶
create table sougou_bucket(uid string,keyword string) comment 'test' clustered by(uid) into 5 buckets row format delimited fields terminated by '\t';
必须使用启动MapReduce作业的方式才能把文件顺利分桶,若使用load data local inpath 这种方式加载数据,即使设置了强制分桶,也不起作用。注意,插入数据之前,需要设置属性hive.enforce.bucketing=true,其含义是数据分桶是否被强制执行,默认为false,如果开启,则写入table数据时会启动分桶。所以必须要将该属性的值设置为true。
set hive.enforce.bucketing=true;
insert overwrite table sogou_bucket select uid,keyword from sogou_500w limit 10000;
分桶表相对于分区表来说的,分桶表在物理结构上一个桶对应一个文件,而分区表一个分区对应一个目录。