一、入门须知
1.1 hive命令
linux查看
hive -help;
查询
hive -e "select * from users";
使用hive命令
sql语句编写:
select '1.0' + 2;
select '111' >1;
select cast('111' as int );
select arr[0] from ( select array(1,2) arr) tmp;
执行脚本中sql语句
-f:执行脚本中sql语句
# 创建文件hqlfile1.sql,内容:
vim hqlfile1.sql
select * from users
# 执行文件中的SQL语句
hive -f hqlfile1.sql
# 执行文件中的SQL语句,将结果写入文件
hive -f hqlfile1.sql >> result1.log
退出Hive命令
exit; quit;
命令行执行 shell 命令 / dfs 命令
hive> ! ls;
hive> ! clear;
hive> dfs -ls / ;
1.2 数据类型
Hive支持关系型数据库的绝大多数基本数据类型,同时也支持4种集合数据类型
1.2.1 基本数据类型
(1)数据类型的隐式转换
Hive会将类型转换成两个浮点类型中值较大的那个类型
即:将FLOAT类型转换成DOUBLE类型;当然如果需要的话,任意整型会转化成DOUBLE类型。
Hive 中基本数据类型遵循以下层次结构
select '1.0'+2;
select '1111' > 10;
select 1 > 0.8;
(2)数据类型的显式转换
使用cast函数进行强制类型转换;如果强制类型转换失败,返回NULL
select cast('1111s' as int);
select cast('1111' as int);
1.2.2 集合数据类型
Hive支持集合数据类型,包括array、map、struct、union
#arry
select array(1,2,3);
select arr[0] from (select array(1,2,3) arr) tmp;
#map
select map('a', 1, 'b', 2, 'c', 3);
select mymap["a"] from (select map('a', 1, 'b', 2, 'c',
3) as mymap) tmp;
select mymap["x"] from (select map('a', 1, 'b', 2, 'c',
3) as mymap) tmp;
#struct
select struct('username1', 7, 1288.68);
select named_struct("name", "username1", "id", 7,"salary", 12880.68);
select userinfo.id from (select named_struct("name", "username1", "id",7, "salary", 12880.68) userinfo) tmp;
select create_union(0, "zhansan", 19, 8000.88) uinfo;
1.2.3 文本文件数据格式
Hive表中的数据在存储在文件系统上,Hive定义了默认的存储格式,也支持用户自定义文件存储格式。
Hive默认使用几个很少出现在字段值中的控制字符,来表示替换默认分隔符的字符。
字段之间:^A
元素之间: ^B
key-value之间:^C
如
mkdir -p /home/hadoop/data
cd /home/hadoop/data
vim s1.dat
666^Alisi^A18^Aread^Bgame^Ajava^C97^Bhadoop^C87
备注:^A 等符号必须敲击键盘:ctrl+V+A ,进行变蓝才有效
^A / ^B / ^C 都是特殊的控制字符,使用 more 、 cat 命令是看不见的;可以使用
cat -A file.dat
create table s1(
id int,
name string,
age int,
hobby array<string>,
score map<string, int>
);
load data local inpath '/home/hadoop/data/s1.dat' into table s1;
select * from s1;
备注:删除数据
truncate table s1;
写时模式和读时模式
在传统数据库中,在加载时发现数据不符合表的定义,则拒绝加载数据。数据在写入数据库时对照表模式进行检查,这种模式称为"写时模式"(schema on write)。
- 写时模式 -> 写数据检查 -> RDBMS;
Hive中数据加载过程采用"读时模式" (schema on read),加载数据时不进行数据格式的校验,读取数据时如果不合法则显示NULL。这种模式的优点是加载数据迅速。
- 读时模式 -> 读时检查数据 -> Hive;好处:加载数据快;问题:数据显示NULL
二、DDL命令
hive使用的sql语言我们称为hql。ddl的命令主要有CREATE、ALTER、DROP等。
Hive有一个默认的数据库default,在操作HQL时,如果不明确的指定要使用哪个库,则使用默认数据库;
Hive的数据库名、表名均不区分大小写;
名字不能使用数字开头;
不能使用关键字,尽量不使用特殊符号;
2.1数据库语法
#创建数据库,在HDFS上存储路径为 /user/hive/warehouse/*.db
create database if not exists mydb;
#查看存储库文件详情
dfs -ls -R /user/hive;
#指定数据库和存储位置
create database if not exists mydb2
comment 'this is mydb2'
location '/user/hive/mydb2.db';
#使用数据库
use mydb;
#删除数据库
-- 删除一个空数据库
drop database databasename;
-- 如果数据库不为空,使用 cascade 强制删除
drop database databasename cascade
2.2建表语法
内部表 & 外部表
在创建表的时候,可指定表的类型。表有两种类型,分别是内部表(管理表)、外部表。
默认情况下,创建内部表。如果要创建外部表,需要使用关键字 external
在删除内部表时,表的定义(元数据) 和 数据 同时被删除
在删除外部表时,仅删除表的定义,数据被保留
在生产环境中,多使用外部表
cd /home/hadoop/data
vim t1.dat
2;zhangsan;book,TV,code;beijing:chaoyang,shagnhai:pudong
3;lishi;book,code;nanjing:jiangning,taiwan:taibei
4;wangwu;music,book;heilongjiang:haerbin
2.2.1 创建内部表
#创建表t1
create table t1(
id int,
name string,
hobby array<string>,
addr map<string, string>
)
row format delimited
fields terminated by ";"
collection items terminated by ","
map keys terminated by ":";
-- 显示表的定义,显示的信息较少
desc t1;
-- 显示表的定义,显示的信息多,格式友好
desc formatted t1;
-- 加载数据
load data local inpath '/home/hadoop/data/t1.dat' into table
t1;
-- 查询数据
select * from t1;
-- 查询数据文件
dfs -ls /user/hive/warehouse/mydb.db/t1;
-- 删除表。表和数据同时被删除
drop table t1;
-- 再次查询数据文件,已经被删除
2.2.2 创建外部表
#创建外部表
create external table t2(
id int,
name string,
hobby array<string>,
addr map<string, string>
)
row format delimited
fields terminated by ";"
collection items terminated by ","
map keys terminated by ":";
-- 显示表的定义
desc formatted t2;
-- 加载数据
load data local inpath '/home/hadoop/data/t1.dat' into table
t2;
-- 查询数据
select * from t2;
-- 删除表。表删除了,目录仍然存在
drop table t2;
-- 再次查询数据文件,仍然存在
-- 内部表转外部表
alter table t1 set tblproperties('EXTERNAL'='TRUE');
-- 查询表信息,是否转换成功
desc formatted t1;
-- 外部表转内部表。EXTERNAL 大写,false 不区分大小
alter table t1 set tblproperties('EXTERNAL'='FALSE');
-- 查询表信息,是否转换成功
desc formatted t1;
2.2.3 分区表
Hive在执行查询时,一般会扫描整个表的数据。由于表的数据量大,全表扫描消耗时间长、效率低。
而有时候,查询只需要扫描表中的一部分数据即可,Hive引入了分区表的概念,将表的数据存储在不同的子目录中,每一个子目录对应一个分区。只查询部分分区数据时,可避免全表扫描,提高查询效率。在实际中,通常根据时间、地区等信息进行分区
分区表创建与数据加载
--创建表
create table if not exists t3(
id int,
name string,
hobby array<string>,
addr map<String,string>
) partitioned by (dt string)
row format delimited
fields terminated by ';'
collection items terminated by ','
map keys terminated by ':';
--加载数据
load data local inpath "/home/hadoop/data/t1.dat"
into table t3 partition(dt="2020-06-01");
load data local inpath "/home/hadoop/data/t1.dat"
into table t3 partition(dt="2020-06-02");
-- 增加多个分区。准备数据
hdfs dfs -cp /user/hive/warehouse/t3/dt=2020-06-01 /user/hive/warehouse/t3/dt=2020-06-07;
hdfs dfs -cp /user/hive/warehouse/t3/dt=2020-06-01 /user/hive/warehouse/t3/dt=2020-06-08;
-- 增加多个分区。加载数据
alter table t3 add
partition(dt='2020-06-07') location
'/user/hive/warehouse/t3/dt=2020-06-07';
alter table t3 add
partition(dt='2020-06-08') location
'/user/hive/warehouse/t3/dt=2020-06-08';
修改分区的hdfs路径
alter table t3 partition(dt='2020-06-01') set location '/user/hive/warehouse/t3/dt=2020-06-03';
删除分区
-- 可以删除一个或多个分区,用逗号隔开
alter table t3 drop partition(dt='2020-06-03'),partition(dt='2020-06-04');
分区表查询
select * from t3 where dt='2020-06-02';
2.2.4 分桶表
当单个的分区或者表的数据量过大,分区不能更细粒度的划分数据,就需要使用分桶技术将数据划分成更细的粒度。将数据按照指定的字段进行分成多个桶中去,即将数据按照字段进行划分,数据按照字段划分到多个文件当中去。
分桶的原理:
MR中:key.hashCode % reductTask
Hive中:分桶字段.hashCode % 分桶个数
cd /home/hadoop/data
vim course.dat;
1 c 78
2 java 52
3 c++ 12
1 c-- 98
创建分桶表
create table course(
id int,
name string,
score int
)
clustered by (id) into 3 buckets
row format delimited fields terminated by "\t";
-- 创建普通表
create table course_common(
id int,
name string,
score int
)
row format delimited fields terminated by "\t";
-- 普通表加载数据
load data local inpath '/home/hadoop/data/course.dat' into
table course_common;
-- 通过 insert ... select ... 给桶表加载数据
insert into table course select * from course_common;
2.3 修改表、删除表
-- 修改表名。rename
alter table course_common
rename to course_common1;
-- 修改列名。change column
alter table course_common1
change column id cid int;
-- 修改字段类型。change column
alter table course_common1
change column cid cid string;
-- The following columns have types incompatible with the
existing columns in their respective positions
-- 修改字段数据类型时,要满足数据类型转换的要求。如int可以转为string,但是
string不能转为int
-- 增加字段。add columns
alter table course_common1
add columns (common string);
-- 删除字段:replace columns
-- 这里仅仅只是在元数据中删除了字段,并没有改动hdfs上的数据文件
alter table course_common1
replace columns(
id string, cname string, score int);
-- 删除表
drop table course_common1;
三、DML
3.1Load数据
创建文件
数据文件(~/data/sourceA.txt):
1,fish1,SZ
2,fish2,SH
3,fish3,HZ
4,fish4,QD
5,fish5,SR
hdfs dfs -mkdir data/;
-- 拷贝文件到 HDFS
hdfs dfs -put sourceA.txt data/;
3.1.1 建表后load数据
-- 创建表
CREATE TABLE tabA (
id int
,name string
,area string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
#方式一:加载本地文件到hive(tabA)
LOAD DATA LOCAL INPATH '/home/hadoop/data/sourceA.txt' INTO TABLE tabA;
#方式二:加载hdfs文件到hive(tabA)
#2.1 数据全部插入
LOAD DATA INPATH 'data/sourceA.txt' INTO TABLE tabA;
#2.2 数据覆盖性插入
hdfs dfs -put sourceA.txt data/;
LOAD DATA INPATH 'data/sourceA.txt' OVERWRITE INTO TABLE tabA;
3.1.2 建表时load数据
-- 创建表时加载数据
hdfs dfs -mkdir /user/hive/tabB
hdfs dfs -put sourceA.txt /user/hive/tabB
CREATE TABLE tabB (
id INT
,name string
,area string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
Location '/user/hive/tabB';
3.2 Insert数据
-- 创建分区表
CREATE TABLE tabC (
id INT
,name string
,area string
)
partitioned by (month string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
1、插入数据
insert into table tabC partition(month='202001')
values (5, 'wangwu', 'BJ'), (4, 'lishi', 'SH'), (3,'zhangsan', 'TJ');
2、插入查询的结果数据
insert into table tabC partition(month='202002')
select id, name, area from tabC where month='202001';
3、多表(多分区)插入模式
from tabC
insert overwrite table tabC partition(month='202003')
select id, name, area where month='202002'
insert overwrite table tabC partition(month='202004')
select id, name, area where month='202002';
4、as语句查询结果创建表
create table if not exists tabD as select * from tabC;
4.1、like tname创建的表结构与原表一致
create table tabE like tabc;
from tabC
insert overwrite table tabE partition(month='202003')
select id, name, area where month='202002'
insert overwrite table tabE partition(month='202004')
select id, name, area where month='202002';
3.3 export数据
3.3.1 将查询结果导出到本地
insert overwrite local directory '/home/hadoop/data/tabC2'
row format delimited fields terminated by ' '
select * from tabC;
3.3.2 将查询结果导出到HDFS
insert overwrite directory '/user/hadoop/data/tabC3'
row format delimited fields terminated by ' '
select * from tabC;
3.3.3 export导出数据
(export方式的导出,可用import进行导入)
export table tabC to '/user/hadoop/data/tabC5';
3.4 import数据
import table student2 from '/user/hadoop/data/tabC5';
3.5 truncate表
-- 截断表,清空数据。(注意:仅能操作内部表)
truncate table tabE;
-- 以下语句报错,外部表不能执行 truncate 操作
alter table tabC set tblproperties("EXTERNAL"="TRUE");
truncate table tabC;
四、DQL命令
创建表和数据
-- 测试数据 /home/hadoop/data/emp.dat
7369,SMITH,CLERK,7902,2010-12-17,800,,20
7499,ALLEN,SALESMAN,7698,2011-02-20,1600,300,30
7521,WARD,SALESMAN,7698,2011-02-22,1250,500,30
7566,JONES,MANAGER,7839,2011-04-02,2975,,20
7654,MARTIN,SALESMAN,7698,2011-09-28,1250,1400,30
7698,BLAKE,MANAGER,7839,2011-05-01,2850,,30
7782,CLARK,MANAGER,7839,2011-06-09,2450,,10
7788,SCOTT,ANALYST,7566,2017-07-13,3000,,20
7839,KING,PRESIDENT,,2011-11-07,5000,,10
7844,TURNER,SALESMAN,7698,2011-09-08,1500,0,30
7876,ADAMS,CLERK,7788,2017-07-13,1100,,20
7900,JAMES,CLERK,7698,2011-12-03,950,,30
7902,FORD,ANALYST,7566,2011-12-03,3000,,20
7934,MILLER,CLERK,7782,2012-01-23,1300,,10
-- 建表并加载数据
CREATE TABLE emp (
empno int,
ename string,
job string,
mgr int,
hiredate DATE,
sal int,
comm int,
deptno int
)row format delimited fields terminated by ",";
-- 加载数据
LOAD DATA LOCAL INPATH '/home/hadoop/data/emp.dat'
INTO TABLE emp;
4.1 全局排序ORDER BY
ORDER BY执行全局排序,只有一个reduce;
select empno, ename, job, mgr, sal + nvl(comm, 0) salcomm,
deptno
from emp
order by deptno, salcomm desc;
4.2 局部排序sort by
-- 设置reduce个数
set mapreduce.job.reduces=2;
-- 按照工资降序查看员工信息
select empno,ename,sal from emp sort by sal desc;
--输出本地
insert overwrite local directory '/home/hadoop/output/sort2'
select empno,ename,sal from emp sort by sal desc;
4.3 分区排序(distribute by)
distribute by 类似于MR中的分区操作,可以结合sort by操作,使分区数据有序;
distribute by 要写在sort by之前;
set mapreduce.job.reduces=3;
select empno,ename,sal,deptno from emp distribute by deptno sort by sal desc;
全局排序、局部排序、分区排序结果比较(按顺序)
order by sort by distribute by & sort by
4.4 Cluster By
当distribute by 与 sort by是同一个字段时,可使用cluster by简化语法;
五 函数
5.1系统内置函数
-- 查看系统自带函数
show functions;
-- 显示自带函数的用法
desc function date_format;
5.1.1 日期函数
-- 当前日期
select current_date;
select current_timestamp;
-- 字符串转时间(字符串必须为:yyyy-MM-dd格式)
select to_date('2020-01-01');
select to_date('2020-01-01 12:12:12');
-- 日期、时间戳、字符串类型格式化输出标准时间格式
select date_format(current_timestamp(), 'yyyy-MM-ddHH:mm:ss');
select date_format(current_date(), 'yyyyMMdd');
select date_format('2020-06-01', 'yyyy-MM-dd HH:mm:ss');
-- 计算日期天差
select datediff('2020-04-18','2019-11-21');
select datediff('2019-11-21', '2020-04-18');
-- 计算emp表中,每个人的工龄
select *, round(datediff(current_date, hiredate)/365,1)
workingyears from emp;
时间戳
--当前时间戳
select unix_timestamp();
-- 时间戳转日期
select from_unixtime(1505456567);
select from_unixtime(1505456567, 'yyyyMMdd');
select from_unixtime(1505456567, 'yyyy-MM-dd HH:mm:ss');
-- 日期转时间戳
select unix_timestamp('2019-09-15 14:23:00');
5.1.2 字符串函数
-- 转小写。lower
select lower("HELLO WORLD");
-- 转大写。upper
select lower(ename), ename from emp;
-- 求字符串长度。length
select length(ename), ename from emp;
-- 字符串拼接。 concat
select concat(empno, " " ,ename) idname from emp;
-- 求子串。substr
SELECT substr('www.lagou.com', 5);
SELECT substr('www.lagou.com', -5);
SELECT substr('www.lagou.com', 5, 5);
-- 指定分隔符。concat_ws(separator, [string | array(string)]+)
SELECT concat_ws('.', 'www', array('lagou', 'com'));
select concat_ws(" ", ename, job) from emp;
-- 字符串切分。split,注意 '.' 要转义
select split("www.lagou.com", "\\.");
5.1.3数字函数
-- 四舍五入。round
select round(314.15926);
select round(314.15926, 2);
select round(314.15926, -2);
-- 向上取整。ceil
select ceil(3.1415926);
-- 向下取整。floor
select floor(3.1415926);
5.1.4 条件函数
为NULL返回指定值
select sal, coalesce(comm, 0) from emp;
select sal, nvl(comm, 0) from emp;
条件查询
-- isnull(a) isnotnull(a)
select * from emp where isnull(comm);
select * from emp where isnotnull(comm);
-- nullif(x, y) 相等为空,否则为a
SELECT nullif("b", "b"), nullif("b", "a");
5.1.5 UDTF函数
(1)explode,炸裂函数
-- 就是将一行中复杂的 array 或者 map 结构拆分成多行
select explode(array('A','B','C')) as col;
select explode(map('a', 8, 'b', 88, 'c', 888));
炸裂函数结果对比
array>> >>>> map>> >>>>
lateral view 常与 表生成函数explode结合使用
with t1 as (
select 'OK' cola, split('www.lagou.com', '\\.') colb
)
select cola, colc
from t1
lateral view explode(colb) t2 as colc;
select 'OK' cola, split('www.lagou.com', '\\.') colb >>> select cola, colc from t1 lateral view explode(colb) t2 as colc;
案例1:
-- 数据(uid tags):
1 1,2,3
2 2,3
3 1,2
--编写sql,实现如下结果:
1 1
1 2
1 3
2 2
2 3
3 1
3 2
vim /home/hadoop/data/market.txt
1 1,2,3
2 2,3
3 1,2
-- 建表加载数据
create table market(
uid int,
tags string
)
row format delimited fields terminated by '\t';
load data local inpath '/home/hadoop/data/market.txt' into table
market;
select uid, tag
from market
lateral view explode(split(tags,",")) t2 as tag;
案例2:找到每个学员的最好成绩
vim /home/hadoop/data/score.dat
lisi|Chinese:90,Math:80,English:70
wangwu|Chinese:88,Math:90,English:96
maliu|Chinese:99,Math:65,English:60
-- 创建表
create table studscore(
name string
,score map<String,string>)
row format delimited
fields terminated by '|'
collection items terminated by ','
map keys terminated by ':';
-- 加载数据
load data local inpath '/home/hadoop/data/score.dat' overwrite
into table studscore;
with tmp as (
select name, subject, mark
from studscore lateral view explode(score) t1 as subject,
mark
)
select name, max(mark) maxscore
from tmp
group by name;
5.2窗口函数
over 关键字
使用窗口函数之前一般要要通过over()进行开窗
--使用窗口函数,查询员工姓名、薪水、薪资水平占比
select ename, sal, sum(sal) over() salsum,
concat(round(sal / sum(sal) over()*100, 1) || '%')
ratiosal
from emp;
partition by子句
select ename, sal, deptno, sum(sal) over(partition by deptno ) salsum from emp;
order by 子句
select ename, sal, deptno, sum(sal)
over(partition by deptno order by sal) salsum from emp;
Window子句
组内,第一行到当前行的和
select ename, sal, deptno,
sum(sal) over(partition by deptno order by ename) from
emp;
组内,第一行到最后一行的和
select ename, sal, deptno,
sum(sal) over(partition by deptno order by ename
rows between unbounded preceding and
unbounded following)
from emp;
同价:
select ename, sal, deptno,
sum(sal) over(partition by deptno) from
emp;
组内,前一行、当前行、后一行的和
select ename, sal, deptno,
sum(sal) over(partition by deptno order by ename
rows between 1 preceding and 1 following
)
from emp;
排名函数
都是从1开始,生成数据项在分组中的排名,有三种排名方式,规则如下
-- row_number / rank / dense_rank
100 1 1 1
100 2 1 1
100 3 1 1
99 4 4 2
98 5 5 3
98 6 5 3
97 7 7 4
vim /home/hadoop/data/t2.dat
class1 s01 100
class1 s03 100
class1 s05 100
class1 s07 99
class1 s09 98
class1 s02 98
class1 s04 97
class2 s21 100
class2 s24 99
class2 s27 99
class2 s22 98
class2 s25 98
class2 s28 97
class2 s26 96
-- 创建表加载数据
create table t2(
cname string,
sname string,
score int
) row format delimited fields terminated by ' ';
load data local inpath '/home/hadoop/data/t2.dat' into table
t2;
-- 按照班级,使用3种方式对成绩进行排名
select cname, sname, score,
row_number() over (partition by cname order by score desc) rank1,
rank() over (partition by cname order by score desc) rank2,
dense_rank() over (partition by cname order by score desc) rank3
from t2;
求每个班级前3名的学员--前3名的定义是什么--假设使用dense_rank
select cname, sname, score, rank
from (select cname, sname, score,
dense_rank() over (partition by cname order by
score desc) rank
from t2) tmp
where rank <= 3;
续:(优化)找到每个学员的最好学科和成绩
with tmp as (
select name, subject, mark
from studscore lateral view explode(score) t1 as subject,
mark
)
select name, subject, mark
from (select name, subject, mark,
dense_rank() over (partition by name order by mark desc) rank
from tmp) tmp
where rank <= 1;
序列函数
-- 建表语句
create table userpv(
cid string,
ctime date,
pv int
)
row format delimited fields terminated by ",";
-- 加载数据
Load data local inpath '/home/hadoop/data/userpv.dat' into
table userpv;
--整体后移或者前移一行
select cid, ctime, pv,
lag(pv) over() lagpv,
lead(pv) over() leadpv
from userpv order by cid;
按分区后移或者前移一行
select cid, ctime, pv,
lag(pv) over(partition by cid order by ctime) lagpv,
lead(pv) over(partition by cid order by ctime) leadpv
from userpv;
按分区后求最后一行和第一行
select cid, ctime, pv,
first_value(pv) over (partition by cid order by ctime
rows between unbounded preceding and unbounded following) as
firstpv,
last_value(pv) over (partition by cid order by ctime
rows between unbounded preceding and unbounded following) as
lastpv
from userpv;
对分区再分组
select cid, ctime, pv,
ntile(2) over(partition by cid order by ctime) ntile
from userpv;
续:(扩展)找到每个学员的成绩、以及最好的成绩
with tmp as (
select name, subject, mark
from studscore lateral view explode(score) t1 as subject,
mark
)
select name, subject, mark,
first_value(mark) over (partition by name order by mark desc
rows between unbounded preceding and unbounded following) as
firstpv
from tmp
六 Hive 事务
- Hive提供行级别的ACID语义
- BEGIN、COMMIT、ROLLBACK 暂时不支持,所有操作自动提交
- 目前只支持 ORC 的文件格式
- 默认事务是关闭的,需要设置开启
- 要是使用事务特性,表必须是分桶的
- 只能使用内部表
- 如果一个表用于ACID写入(INSERT、UPDATE、DELETE),必须在表中设置表
- 属性 : "transactional=true"
- 必须使用事务管理器 org.apache.hadoop.hive.ql.lockmgr.DbTxnManager
- 目前支持快照级别的隔离。就是当一次数据查询时,会提供一个数据一致性的快照
- LOAD DATA语句目前在事务表中暂时不支持
-- 这些参数也可以设置在hive-site.xml中
SET hive.support.concurrency = true;
SET hive.exec.dynamic.partition.mode = nonstrict;
SET hive.txn.manager =
org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
create table zxz_data(
name string,
nid int,
phone string,
ntime date)
clustered by(nid) into 5 buckets
stored as orc
tblproperties('transactional'='true');
-- 创建临时表,用于向分桶表插入数据
create table temp1(
name string,
nid int,
phone string,
ntime date)
row format delimited
fields terminated by ",";
-- 检查数据和文件
select * from zxz_data;
dfs -ls /user/hive/warehouse/mydb.db/mydb.db/zxz_data ;
-- DML 操作
delete from zxz_data where nid = 3;
dfs -ls /user/hive/warehouse/mydb.db/mydb.db/zxz_data ;
insert into zxz_data values ("name3", 3, "010-83596208",
current_date); -- 不支持
insert into zxz_data values ("name3", 3, "010-83596208",
"2020-06-01"); -- 执行
insert into zxz_data select "name3", 3, "010-83596208",
current_date;
dfs -ls /user/hive/warehouse/mydb.db/mydb.db/zxz_data ;
insert into zxz_data values
("name6", 6, "010-83596208", "2020-06-02"),
("name7", 7, "010-83596208", "2020-06-03"),
("name8", 9, "010-83596208", "2020-06-05"),
("name9", 8, "010-83596208", "2020-06-06");
dfs -ls /user/hive/warehouse/mydb.db/mydb.db/zxz_data ;
update zxz_data set name=concat(name, "00") where nid>3;
dfs -ls /user/hive/warehouse/mydb.db/mydb.db/zxz_data ;
发送每次都会生成一批新的文件
七 元数据管理与存储
7.1 metastore远程连接模式
在生产环境中,建议用远程模式来配置Hive Metastore。
在这种模式下,其他依赖hive的软件都可以通过Metastore访问Hive。此时需要配置
hive.metastore.uris 参数来指定 metastore 服务运行的机器ip和端口,并且需要单
独手动启动metastore服务。metastore服务可以配置多个节点上
安装计划:
节点 | metastore | client |
linux26 | √ | |
linux127 | √ | |
linux128 | √ |
1、将 linux126 的 hive 安装文件拷贝到 linux127、linux128
在linux126上
cd /opt/lagou/servers
rsync-script hive-2.3.7/
在 linux127、linux128上配置hive的环境变量
2、在linux126、linux128上分别启动 metastore 服务
# 启动 metastore 服务
nohup hive --service metastore &# 安装lsof
yum install lsof
# 查询9083端口(metastore服务占用的端口)
lsof -i:9083修改 linux122 上hive-site.xml。删除配置文件中:MySQL的配置、连接数据库 的用户名、口令等信息;增加连接metastore的配置:
<!-- hive metastore 服务地址 --> <property> <name>hive.metastore.uris</name> <value>thrift://linux126:9083,thrift://linux128:9083</value> </property>
linux127上启动hive。
[root@linux127~]$ hive
此时client端无需实例化hive的metastore,启动速度会加快。
7.2 HiveServer2
HiveServer2(HS2)是一种允许客户端对Hive执行查询的服务
安装计划
节点 | HiveServer2 | client |
linux126 | √ | |
linux127 | √ | |
linux128 |
1、修改 linux126上hadoop的 core-site.xml,增加以下内容:
<!-- HiveServer2 连不上10000;hadoop为安装用户 -->
<!-- root用户可以代理所有主机上的所有用户 -->
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hadoop.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hadoop.groups</name>
<value>*</value>
</property>
2、修改 linux126上hadoop的 hdfs-site.xml,增加以下内容:
<!-- HiveServer2 连不上10000;启用 webhdfs 服务 -->
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
把修改同步到节点上
scp hdfs-site.xml linux127:$PWD
scp hdfs-site.xml linux128:$PWD
scp core-site.xml linux127:$PWD
scp core-site.xml linux128:$PWD
在linux126上重启hdfs
start-dfs.sh
在linux128上启动hiveserver2
nohup hiveserver2 &
lsof -i:10000
连接
在linux127上
cd /opt/servers/hive-2.3.7/bin
./beeline
!connect jdbc:hive2://linux128:10000
输入用户名和密码 (root/12345678)
show databases;
7.3 HCatalog
HCatalog 提供了一个统一的元数据服务,允许不同的工具如 Pig、MapReduce 等通过 HCatalog 直接访问存储在 HDFS 上的底层文件(装了hive就可以使用)
# 进入 hcat 所在目录。$HIVE_HOME/hcatalog/bin
cd $HIVE_HOME/hcatalog/bin
# 查看元数据
./hcat -e "use mydb; show tables"
./hcat -e "desc mydb.emp"
# 删除表
./hcat -e "drop table default.test1"
7.4 数据存储格式
Hive支持的存储数的格式主要有:TEXTFILE(默认格式) 、SEQUENCEFILE、RCFILE、ORCFILE、PARQUET。
textfile为默认格式,建表时没有指定文件格式,则使用TEXTFILE,导入数据时会直接把数据文件拷贝到hdfs上不进行处理;
sequencefile,rcfile,orcfile格式的表不能直接从本地文件导入数据,数据要先导入到textfile格式的表中, 然后再从表中用insert导入sequencefile、rcfile、orcfile表中。
#行存储与列存储
行式存储下一张表的数据都是放在一起的,但列式存储下数据被分开保存了。
#行式存储:
优点:数据被保存在一起,insert和update更加容易
缺点:选择(selection)时即使只涉及某几列,所有数据也都会被读取
#列式存储:
优点:查询时只有涉及到的列会被读取,效率高
缺点:选中的列要重新组装,insert/update比较麻烦
TEXTFILE、SEQUENCEFILE 的存储格式是基于行存储的;
ORC和PARQUET 是基于列式存储的。
7.4.1 TextFile
Hive默认的数据存储格式,数据不做压缩,磁盘开销大,数据解析开销大。 可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
create table if not exists uaction_text(
userid string,
itemid string,
behaviortype int,
geohash string,
itemcategory string,
time string)
row format delimited fields terminated by ','
stored as textfile;
load data local inpath '/home/hadoop/data/uaction.dat'
overwrite into table uaction_text;
7.4.2 SEQUENCEFILE
SequenceFile是Hadoop API提供的一种二进制文件格式,其具有使用方便、可分割、可压缩的特点。
SequenceFile支持三种压缩选择:none,record,block。
Record压缩率低,一般建议使用BLOCK压缩。
7.4.3 RCFile
RCFile全称Record Columnar File,列式记录文件,是一种类似于SequenceFile的键值对数据文件。
RCFile结合列存储和行存储的优缺点,是基于行列混合存储的RCFile。
RCFile遵循的“先水平划分,再垂直划分”的设计理念。先将数据按行水平划分为行组,这样一行的数据就可以保证存储在同一个集群节点;然后在对行进行垂直划分。
7.4.4 ORCFile
ORC File,它的全名是Optimized Row Columnar (ORC) file,其实就是对RCFile做了一些优化,在hive 0.11中引入的存储格式。
这种文件格式可以提供一种高效的方法来存储Hive数据。它的设计目标是来克服Hive其他格式的缺陷。
运用ORC File可以提高Hive的读、写以及处理数据的性能。
ORC文件结构由三部分组成:
(1)文件脚注(file footer):包含了文件中 stripe 的列表,每个stripe行数,以及每个列的数据类型。还包括每个列的最大、最小值、行计数、求和等信息
(2)postscript:压缩参数和压缩大小相关信息
(3)条带(stripe):ORC文件存储数据的地方。在默认情况下,一个stripe的大小为
250MB
- Index Data:
一个轻量级的index,默认是每隔1W行做一个索引。包括该条带的一些统计信息,以及数据在stripe中的位置索引信息
- Rows Data:
存放实际的数据。先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个stream来存储
- Stripe Footer:
存放stripe的元数据信息
ORC在每个文件中提供了3个级别的索引:文件级、条带级、行组级。
借助ORC提供的索引信息能加快数据查找和读取效率,规避大部分不满足条件的查询条件的文件和数据块。
使用ORC可以避免磁盘和网络IO的浪费,提升程序效率,提升整个集群的工作负载。
create table if not exists uaction_orc(
userid string,
itemid string,
behaviortype int,
geohash string,
itemcategory string,
time string)
stored as orc;
insert overwrite table uaction_orc select * from uaction_text;
7.4.5 Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Mapreduce、Spark等),被多种查询引擎支持(Hive、Impala、Drill等),与语言和平台无关的。
Parquet文件是以二进制方式存储的,不能直接读取的,文件中包括实际数据和元数据,Parquet格式文件是自解析的。
create table if not exists uaction_parquet(
userid string,
itemid string,
behaviortype int,
geohash string,
itemcategory string,
time string)
stored as parquet;
insert overwrite table uaction_parquet select * from
uaction_text;
7.4.6 文件存储格式对比测试
文件压缩比:ORC > Parquet > text
执行查询:orc 与 parquet类似 > txt
在生产环境中,Hive表的数据格式使用最多的有三种:TextFile、ORCFile、Parquet。
- TextFile文件更多的是作为跳板来使用(即方便将数据转为其他格式)
- 有update、delete和事务性操作的需求,通常选择ORCFile
- 没有事务性要求,希望支持Impala、Spark,建议选择Parquet
分解数据文件大小(文件数据量如果太大,可以视电脑性能而定,选择合适行数,进行压缩比和查询速率比测试)
wc -l uaction.dat
head -n 100000 uaction.dat -> t1.dat