大数据课程F3——HIve的基本操作

文章作者邮箱:[email protected]              地址:广东惠州

 ▲ 本章节目的

⚪ 掌握HIve的基本SQL语句和注意问题;

⚪ 掌握HIve的表结构;

⚪ 掌握HIve的数据类型;

⚪ 掌握HIve的基础函数和窗口函数;

一、基本SQL

1. SQL的执行方式

1. 通过hive -e的方式来执行指定的SQL,例如hive -e 'create database demo;'。

2. 通过hive -f的方式来执行指定的SQL脚本,例如hive -f test.sql。

3. 进入Hive的命令行里来执行指定的SQL。

2. 注意问题

1. 如果不指定,那么Hive默认将数据放在HDFS的/user/hive/warehouse目录下。

2. 在Hive中,每一个database都对应了一个单独的目录。

3. 在Hive启动的时候,自带一个default库。如果在建表的时候没有指定,那么默认也是将表放在default库下。

4. alter database可以修改指定库的属性,但是不能修改库的库名以及存储位置。

5. 在Hive中,没有主键的概念,不支持主键。

6. 在Hive中,每一个table也对应了一个单独的目录。

7. 在Hive中,需要在建表的时候指定字段之间的间隔符号。

8. insert into表示向表中追加数据;insert overwrite表示将表中的清空之后再添加当前的数据(覆盖)。

9. 需要注意的是,Hive中的数据会以文件的形式落地到HDFS上,在Hive的默认文件格式(textfile - 文本)下,不支持修改(update和delete)操作。如果需要Hive支持修改操作,那么需要在建表的时候指定文件格式为orc格式。但是在实际开发中,因为一般利用Hive存储历史数据,所以很少或者根本不对Hive中的数据进行修改,因此一般不适用orc格式。另外,orc格式虽然支持update和delete操作,但是效率非常低。

3. 基本SQL

SQL

解释

create database demo;

创建demo库

create database if not exists demo4;

如果demo4库不存在,则创建

create database demo5 location '/demo5';

创建demo5库,同时指定存储位置

show databases;

查看所有的库

show databases like 'demo*';

查看demo开头的库

desc database demo;

描述demo库

desc database extended demo;

描述demo库的详细信息

use demo;

使用demo库

alter database demo set dbproperties ('date'='2020-12-25');

修改demo库的属性

drop database demo5;

删除demo5库

drop database if exists demo4;

如果demo4库存在,则删除

drop database demo3 cascade;

强制删除demo3库及其中的表

create table person (id int, name string, age int);

建立person表,包含id,name,age三个字段

insert into table person values(1, 'colin', 19);

插入数据

select * from person;

查询数据

load data local inpath '/home/hivedemo/person.txt' into table person;

从本地加载文件到Hive表中

drop table person;

删除表

create table person (id int, name string, age int) row format delimited fields terminated by ' ';

建表,指定字段之间的间隔符号为空格

create table p2 like person;

创建和person表结构一致的p2表

describe p2;

或者

desc p2;

描述p2

show tables;

查看所有的表

insert into table p2 select * from person where age >= 18;

从person中查询数据,将age>=18的数据放到p2表中

create table if not exists p3 like person;

如果p3表不存在,则创建和person结构一致的p3表

from person insert overwrite table p2 select * where age >= 18 insert into table p3 select * where id < 5;

从person表中查询数据,然后将查询出来的age>=18的数据覆盖到p2表中,同时将id<5的数据追加到p3表中

create table if not exists p4 as select * from person where age < 18;

创建p4表,同时在建表的时候,将person表中age<18的数据放进去

insert overwrite local directory '/home/hivedata' row format delimited fields terminated by '\t' select * from person where age >= 18;

将person表中age>=18的数据查询出来放到本地磁盘的/home/hivedata目录下

insert overwrite directory '/person' row format delimited fields terminated by ',' select * from person where id >= 6;

将person表中id>=6的数据查询出来放到HDFS的地址路径下

alter table person rename to p1;

重命名表

二、基本表结构

1. 内部表和外部表

1. 如果在Hive中手动建表手动添加数据(包括insert和load方式),那么这种表称之为内部表。

2. 如果在Hive中手动建表来管理HDFS上已经存在的数据,那么这种表称之为外部表。

3. 相对而言,在工程或者项目建立的初期,一般会建立外部表来管理HDFS上已经存在的数据;但是当外部表建立之后,不代表数据能够直接处理使用,还需要对数据进行抽取整理等清洗操作,来建立能够实际使用的内部表。

4. 建立外部表:

create external table orders(orderid int, orderdate string, productid int, num int) row format delimited fields terminated by ' ' location '/orders';

5. 查看表的详细信息:

desc extended orders;

#或者

desc formatted orders;

#在其中寻找Table Type:EXTERNAL_TABLE

6. 在Hive中,删除内部表的时候,这个表对应的目录也会从HDFS上删除;删除外部表的时候,只是删除了元数据,而这个表对应的目录没有从HDFS上移除。

2. 分区表

1. 分区表的作用通常是对数据来进行分类。

2. 建立分区表:

create table cities (id int, name string) partitioned by (province string) row format delimited fields terminated by ' ' ;

3. 加载数据:

load data local inpath '/home/hivedemo/hebei.txt' into table cities partition(province='hebei');

load data local inpath '/home/hivedemo/jiangsu.txt' into table cities partition(province='jiangsu');

4. 在Hive中,每一个分区对应一个单独的目录。

5. 如果在查询数据的时候,指定了分区字段,那么分区表的查询效率就会高于未分区的表;如果在查询数据的时候,进行了跨分区查询,那么此时未分区表的查询效率就要高于分区表。

6. 删除分区:

alter table cities drop partition(province = 'henan');

7. 手动添加分区:

alter table cities add partition (province='henan') location '/user/hive/warehouse/demo.db/cities/province=henan';

8. 修复表:

msck repair table cities;

9. 修改分区名:

alter table cities partition(province='__HIVE_DEFAULT_PARTITION__') rename to partition (province='sichuan');

10. 在Hive的分区表中,分区字段在原始数据中并不存在,而是在加载数据的时候来手动指定。如果分区字段在原始数据中存在,那么需要考虑动态分区。

11. 动态分区 - 将未分区表中的数据查询出来放到分区表中:

#建立临时表去管理原始数据

create table cities_tmp (tid int, tprovince string, tcity_name string) row format delimited fields terminated by ' ';

#将数据加载到临时表中

load data local inpath '/home/hivedemo/cities.txt' into table cities_tmp;

#关闭严格模式,开启动态分区

set hive.exec.dynamic.partition.mode=nonstrict;

#将未分区表中的数据查询出来放到分区表中

insert into table cities partition(province) select tid, tcity_name, tprovince from cities_tmp distribute by tprovince;

12. 在Hive中,也允许对多字段来进行分区。此时,前一个字段形成的目录会包含后一个字段形成的目录。多字段分区通常用于对数据来进行多级分类,例如省市县,学生的年级和班级,商品的分类等。

#原始数据

1 1 1 tom

1 1 2 sam

1 1 3 bob

1 1 4 alex

1 2 1 bruce

1 2 2 cindy

1 2 3 jack

1 2 4 john

2 1 1 tex

2 1 2 helen

2 1 3 charles

2 1 4 frank

2 2 1 david

2 2 2 simon

2 2 3 lucy

2 2 4 lily

#建立临时表来管理数据

create table students_tmp (grade int, class int, id int, name string) row format delimited fields terminated by ' ';

#加载数据

load data local inpath '/home/hivedemo/students.txt' into table students_tmp;

#根据年纪和班级,将学生区分开 - 建立分区表

create table students(id int, name string) partitioned by (grade int, class int) row format delimited fields terminated by ' ';

#动态分区

insert into students partition(grade, class) select id, name, grade, class from students_tmp distribute by grade, class;

3. 分桶表

1. 分桶表的作用是对数据进行抽样。

2. 在实际生产过程中,当数据量比较大,且又希望对数据进行快速分析获取分析结果,并且还能够容忍一定程度上的分析误差的时候,可以考虑对数据进行抽样处理。需要注意的是,在抽样的时候,抽样字段和要分析的字段之间不能又关联性。例如年龄和身高之间就是又关联性的,姓名和身高之间是没有关联性的。

3. 在Hive中,分桶机制默认是不开启的,首先需要开启分桶机制。

set hive.enforce.bucketing = true;

4. 建立分桶表 - 桶数指定的越多,执行分桶的时候耗费的资源越多。

create table students_bucket(id int, name string) clustered by (name) into 4 buckets row format delimited fields terminated by '\t';

5. 在Hive中,向分桶表中添加数据的时候,只能使用insert方式而不能使用load方式,使用load方式不会对数据进行分桶。

insert overwrite table students_bucket select id, name from students;

6. 每一个桶都会对应一个单独的结果文件。

7. 对数据进行抽样。

select * from students_bucket tablesample (bucket 1 out of 2 on name);

8. bucket x out of y,x表示从第一个桶的第几行开始抽,y表示抽样步长,即每几行抽一次。

三、数据类型

1. 概述

1. 在Hive中,提供了非常丰富的数据类型,大概可以分为两类:基本类型和复杂类型。

2. 基本类型包含:tinyint,smallint,int,bigint,float,double,boolean,string,timestamp,binary。

3. 复杂类型包含:array,map和struct。

2. 复杂类型

1. array类型:数组类型,对应了Java中的数组或者集合(List和Set)类型。

#原始数据

1 bob,alex lucy,lily,jack

2 tom,sam,smith rose,john

3 peter,bruce david,kathy

4 helen,eden,iran cindy,grace,mike

#建表语句

create table battles (id int, groupa array, groupb array) row format delimited fields terminated by ' ' collection items terminated by ',';

#加载数据

load data local inpath '/home/hivedemo/battles.txt' into table battles;

#非空查询

select groupa[2] from battles where groupa[2] is not null;

2. map类型:映射类型,对应了Java中的映射(Map)类型。

#原始数据

1 tom,87

2 job,69

3 alex,72

4 david,85

5 zoo,90

#建表语句

create table scores(id int, score map) row format delimited fields terminated by ' ' map keys terminated by ',';

#加载数据

load data local inpath '/home/hivedemo/scores.txt' into table scores;

#非空查询

select score['david'] from scores where score['david'] is not null;

3. struct类型:结构体类型,对应了Java中的对象,在使用的时候会将数据封装成一个类似于json串的结构。

#原始数据

1 tom,19,male sam,20,male

2 lily,18,female lucy,18,female

3 charles,19,male mark,21,male

4 joan,18,female james,20,male

5 linda,19,female matin,19,male

#建表语句

create table infos(groupid int, membera struct, memberb struct) row format delimited fields terminated by ' ' collection items terminated by ',';

#加载数据

load data local inpath '/home/hivedemo/infos.txt' into table infos;

#获取指定属性的值

select membera.name from infos;

四、函数

1. 概述

1. 在Hive中,提供了非常丰富的运算符和函数,以方便用户对数据进行处理。

2. 如果Hive中原生提供的函数不能适应当前场景,还可以考虑自定函数。

3. 在Hive中,所有的函数都不能直接使用,必须结合select形成语句才能使用。

4. 查看Hive中的所有函数:

show functions;

5. 描述函数的信息:

desc function count;

2. 案例

1. 拼接多个字符串,并且在拼接的时候指定字符串之间的间隔符号。

#原始数据

mail qq com

music qq com

news baidu com

mail 163 com

#建表语句

create table webs(app string, company string, kind string) row format delimited fields terminated by ' ';

#加载数据

load data local inpath '/home/hivedemo/webs.txt' into table webs;

#字符串拼接

select concat(app, '.', company, '.', kind) from webs;

select concat_ws('.', app, company, kind) from webs;

select concat_ws('.', *) from webs;

2. 给定一个字符串表示日期,从日期中将年份提取出来。

#方式一:切分

select cast(split('2020-12-25', '-')[0] as int);

#方式二:提取

select year('2020-12-25');

3. year函数在使用的时候,要求年月日之间必须用-来拼接,如果用其他符号拼接,那么就无法提取。

#方式一:切分

select cast(split('2020/12/25', '/')[0] as int);

#方式二:替换之后再进行提取

select year(regexp_replace('2020/12/25', '/', '-'));

4. 提取邮箱后缀

#方式一:切分

select split('[email protected]', '@')[1];

#方式二:正则提取

select regexp_extract('[email protected]', '(.+)@(.+)', 2);

3. nvl函数

1. nvl(s1, s2):如果s1的值不为null,那么返回s1的值;如果s1的值为null那么返回s2的值;如果s1和s2的值都为null,那么返回null。

2. 案例:

#原始数据

1 Bill 1000

2 vincent 800

3 William 500

4 Henry

5 Betty 500

6 Fred 300

7 Karl

8 Lee 400

9 Thomas 600

10 Shirley 900

#建表语句

create table rewards(id int, name string, reward double) row format delimited fields terminated by ' ';

#加载数据

load data local inpath '/home/hivedemo/rewards.txt' into table rewards;

#计算平均每一个员工收到了多少的奖金 - 聚合函数在计算的时候,如果碰到null会自动忽略

select avg(nvl(reward, 0)) from rewards;

4. case when函数

1. case when函数:类似于Java中的switch-case结构。

2. 案例:

#原始数据

1 财务 bill 男

2 技术 charles 男

3 技术 lucy 女

4 技术 lily 女

5 财务 helen 女

6 财务 jack 男

7 财务 john 男

8 技术 alex 男

9 技术 cindy 女

10 技术 david 男

#建表语句

create table employers(id int, department string, name string, gender string) row format delimited fields terminated by ' ';

#加载数据

load data local inpath '/home/hivedemo/employers.txt' into table employers;

#统计每一个部门的总人数

select department, count(*) from employers group by department;

#统计每一个部门男女生的总人数

select department, sum(case gender when '男' then 1 else 0 end) as sum_male, sum(case gender when '女' then 1 else 0 end) as sum_female from employers group by department;

5. explode

1. explode(array/map)函数在使用的时候,会传入的数组中的每一个元素给单独提取出来形成单独的一行,或者会将映射中的键值对给拆分开形成多行数据。

2. 案例:单词统计:

#原始数据

hello tom hello bob david joy hello

hello rose joy hello rose

jerry hello tom hello joy

hello rose joy tom hello david

#建表语句

create external table words(warr array) row format delimited collection items terminated by ' ' location '/words';

select w, count(w) from (select explode(warr) w from words)ws group by w;

6. 列转行

1. 所谓的列转行,是将一列的数据进行拆分,拆分成多行的数据。

2. 案例一:

#原始数据

悬崖之上 剧情/动作/悬疑

秘密访客 悬疑/惊悚

扫黑·决战 剧情/动作/犯罪

真·三国无双 动作/奇幻/古装

#建表语句

create table movies(name string, kinds array) row format delimited fields terminated by ' ' collection items terminated by'/';

#加载数据

load data local inpath '/home/hivedemo/movies.txt' into table movies;

#列转行 - 炸裂

select name, kind from movies lateral view explode(kinds) k as kind;

#查询所有的悬疑片

select * from (select name, kind from movies lateral view explode(kinds) k as kind)tmp where kind = '悬疑';

3. 案例二:

#原始数据

Kevin 活泼/开朗 打篮球/看电影

Lisa 大方/活泼 看电影/听音乐

Carl 活泼/幽默 听音乐/打篮球

Joy 大方/诙谐 打游戏/看电影

#建表语句

create table friends (name string, characters array, hobbies array) row format delimited fields terminated by ' ' collection items terminated by '/';

#加载数据

load data local inpath '/home/hivedemo/friends.txt' into table friends;

#炸裂

select name, c, h from friends lateral view explode(characters) c_tmp as c lateral view explode(hobbies) h_tmp as h;

#获取性格活泼喜欢听音乐的人

select * from (select name, c, h from friends lateral view explode(characters) c_tmp as c lateral view explode(hobbies) h_tmp as h) tmp where c = '活泼' and h = '听音乐';

7. 行转列

1. 行转列指的是将多行的数据拼接之后放到一列上。

2. 案例一:

#原始数据

夺命手术 剧情

夺命手术 悬疑

夺命手术 惊悚

夺命手术 犯罪

白夜行 爱情

白夜行 悬疑

如月疑云 喜剧

如月疑云 悬疑

无罪之最 剧情

无罪之最 悬疑

无罪之最 惊悚

无罪之最 犯罪

#建表语句

create table movies (name string, kind string) row format delimited fields terminated by ' ';

#加载数据

load data local inpath '/home/hivedemo/movies.txt' into table movies;

#行转列

select name, concat_ws('/', collect_set(kind)) from movies group by name;

 

3. 案例二:

#原始数据

1 1 burt

1 2 james

1 3 fred

1 4 bruce

1 1 carol

1 2 taylor

1 3 evan

1 4 grace

1 1 richard

1 2 adam

1 3 ben

1 4 ross

1 1 charles

1 2 cody

1 3 wendy

1 4 david

#建表语句

create table students(grade int, class int, name string) row format delimited fields terminated by ' ' ;

#加载数据

load data local inpath '/home/hivedemo/students.txt' into table students;

#行转列

select grade, class, concat_ws(',', collect_list(name)) from students group by grade, class;

8. 分类

1. 在Hive中,对常见的函数进行了分类,分为了3类:

a. UDF(User Defined Function):用户定义函数。特点是一进一出,指的是输入一行数据会获取到一行结果,例如year,length,concat,concat_ws,split等。

b. UDAF(User Defined Aggregation Function):用户定义聚合函数。特点是多进一出,指的是输入多行数据获取到一行结果,例如count,sum,avg,max,min,collect_set,collect_list等。

c. UDTF(User Defined Table-generation Function):用户定义表生成函数。特点是一进多出,指的是输入一行数据获取到多行结果,例如explode。UDTF在使用的时候必须紧贴select语句,例如select explode(XXX) from xxx;并且注意,UDTF在结合select使用的时候,在表输中只能单独存在,例如select name, explode(xxx) from xxx;或者select explode(xxx), name from xxx是不允许的。

2. 在Hive中,相对使用比较多的函数大部分都是UDF函数。

9. 自定义UDF

1. 在Hive中,如果Hive原生提供的函数不能够处理当前的数据,那么Hive允许用户自定义函数。

2. 在Hive1.X和Hive2.X,需要定义类继承UDF类,但是在Hive3.X中,UDF类已过时,所以需要定义类继承GenericUDF类。

3. 定义完类之后,需要将这个类打成jar包放到Linux上,上传之后需要在Hive中来添加当前的jar包。

add jar /home/hivedemo/hive-1.0-SNAPSHOT.jar;

4. 创建临时函数。

create temporary function indexof as 'cn.tedu.hive.udf.AuthUDF';

10. 自定义UDTF

1. 在Hive中,自定义UDTF过程和自定义UDF过程有些类似,不同的地方在于需要定义一个类继承GenericUDTF。

2. 定义完类之后,同样需要将这个类打成jar包放到Linux上,之后同样需要在Hive中添加当前的jar包,同样需要创建临时函数。

五、窗口函数

1. over

1. 窗口函数的作用是用于限制要处理的数据的量。

2. 语法:

分析函数 over(partition by 列名 order by 列名 rows between 起始位置 and 结束位置)

a. 分析函数一般包括聚合函数、排序函数等,例如:

Ⅰ. count(col):统计指定列的总的个数。

Ⅱ. sum(col):针对指定列进行求和。

Ⅲ. avg(col):针对指定列进行求平均。

Ⅳ. max(col):获取指定列的最大值。

Ⅴ. min(col):获取指定列的最小值。

Ⅵ. lag(col, n):获取当前行的第前n行数据。例如lag(col, 1)表示获取上一行数据。再例如,如果当前是第5行数据,那么lag(col, 3)表示获取第2行数据。

Ⅶ. lead(col, n):获取当前的第后n行数据。例如lead(col, 1)表示获取下一行数据。再例如,如果当前是第5行数据,那么lead(col, 3)表示获取第8行数据。

Ⅷ. ntile(n):要求数据必须排序,数据排序之后,会平均的放到n个桶中。Hive自动的给每一个桶进行编号,编号是从1开始。每一个桶中的数据都会携带当前桶的编号。如果数据不能平均放到每一个桶中,那么会优先将排在前面的数据放到小的桶中去,并且,每一个桶中的数据行数之差不能超过1行。

Ⅸ. row_number():在数据排序之后对数据进行自增的编号,且编号不重复。

Ⅹ. rank():在数据排序之后会对数据进行自增的编号,如果值相同,那么编号会重复且产生空位。

ⅩⅠ. dense_rank():在数据排序之后会对数据进行自增的编号,如果值相同,那么编号会重复且不产生空位。

b. partition by:对数据进行分区,实际上就是对数据进行分类

c. order by:对数据进行排序,desc表示降序,asc表示升序

d. rows between:表示指定数据的处理范围

3. 指定范围

a. preceding:往前

b. following:往后

c. current row:当前行

d. unbounded:无边界

Ⅰ. unbounded preceding:从第一行开始

Ⅱ. unbounded following:到最后一行结束

2. 案例

1. 案例一:

#原始数据

jack,2017-01-01,10

tony,2017-01-02,15

jack,2017-02-03,23

tony,2017-01-04,29

jack,2017-01-05,46

jack,2017-04-06,42

tony,2017-01-07,50

jack,2017-01-08,55

mart,2017-04-08,62

mart,2017-04-09,68

neil,2017-05-10,12

mart,2017-04-11,75

neil,2017-06-12,80

mart,2017-04-13,94

#建表语句

create table orders (name string, orderdate string, cost double) row format delimited fields terminated by ',';

#加载数据

load data local inpath '/home/hivedemo/orders.txt' into table orders;

#需求一:查询2017年4月份消费的顾客名单以及2017年4月份产生的总的消费人次

select distinct name, count(*) over() from orders where year(orderdate) = 2017 and month(orderdate) = 4;

#需求二:获取每一个顾客的消费明细以及每一位顾客的月度消费总额

select *, sum(cost) over(partition by name, month(orderdate)) from orders;

#需求三:获取每一个顾客的消费明细以及到当前日期为止的累计消费

select *, sum(cost) over(partition by name order by orderdate rows between unbounded preceding and current row) from orders;

#需求四:查询顾客的消费明细以及每一次消费之后上一次的消费时间

select *, lag(orderdate, 1) over(partition by name order by orderdate) from orders;

#需求五:获取最早的20%的顾客的消费名单 - 首先需要先将数据按照消费日期来进行排序,其次需要将按照排序之后的结果将数据放到5个桶中,获取第一个桶的数据

select * from (select *, ntile(5) over(order by orderdate) as bucket_id from orders)tmp where bucket_id = 1;

2. 案例二:

#原始数据

Charles        Chinese        87

Charles        Math        95

Charles        English        68

Lily        Chinese        94

Lily        Math        56

Lily        English        84

William        Chinese        64

William        Math        86

William        English        84

Vincent        Chinese        65

Vincent        Math        85

Vincent        English        78

#建表语句

create table scores (name string, subject string, score int) row format delimited fields terminated by '\t';

#加载数据

load data local inpath '/home/hivedemo/scores.txt' into table scores;

#需求一:按学科,对每一个学生的成绩进行降序排序

#顺次排序

select *, row_number() over(partition by subject order by score desc) from scores;

#并列排序

select *, rank() over(partition by subject order by score desc) from scores;

#非空位并列排序

select *, dense_rank() over(partition by subject order by score desc) from scores;

#需求二:按学科,获取每一个学科考试成绩前三名的学生

select * from (select *, rank() over(partition by subject order by score desc) as sortid from scores)tmp where sortid <= 3;

 

你可能感兴趣的:(大数据,hive,hadoop)