FaceBook网站每天产生海量的结构化日志数据,为了对这些数据进行管理,并且因为机器学习的需求,产生了hive这门技术,并继续发展成为一个成功的Apache项目。
hive是一个构建在Hadoop上的数据仓库工具(框架),可以将hdfs上的结构化的数据文件映射成一张数据表,并可以使用类SQL语句来对这样的数据文件进行查询统计的功能。hive是一个Hadoop客户端,本质是将SQL语句转化成MapReduce程序。
所以Hive不存储数据,也没有任何计算功能,只是相当于类SQL语句与Hadoop文件之间的一个解释器。其本质是一个对HDFS上的文件进行索引并计算的工具。需要依赖Hadoop的yarn来进行资源分配,也需要Hadoop的MapReduce来提供计算支持。
总结:
Hive中每张表的数据存储在HDFS
Hive分析数据底层的实现是MapReduce(也可以配置为Spark或者Tez)
执行程序运行在Yarn上
Hive底层的实现是MapReduce,但是直接使用MapReduce,需要面临以下问题:
- 人员学习成本高
- 项目周期要求太短
- MapReduce实现复杂查询逻辑开发难度大
1、用户接口:client
CLI:是指Shell命令行
JDBC/ODBC:是指Hive的java实现,与传统数据库JDBC类似。
WebUI:是指可通过浏览器访问Hive。
JDBC和ODBC的区别:
1. JDBC的移植性比ODBC好
2. 两者使用的语言不同,JDBC在Java编程时使用,ODBC一般在C/C++使用
2、元数据:Meta store
元数据包括:数据库(默认是default)、表名、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。
默认存储在 自带的derby数据库中,由于derby数据库只支持但客户端访问,生产环境中为了多人开发,推荐使用MySQL存储Metastore。
3、驱动器:Driver
- 解析器(SQLParser):
将HQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。
- 编译器(Compiler):
对hql语句进行词法、语法、语义的编译(需要跟元数据关联),编译完成后会生成一个执行计划。hive上就是编译成mapreduce的job。
- 优化器(Optimizer):
将执行计划进行优化,减少不必要的列、使用分区、使用索引等。优化job。
- 执行器(Executer):
将优化后的执行计划提交给hadoop的yarn上执行。提交job。
4、Hadoop
使用HDFS进行存储,使用MapReduce进行计算。
1.学习成本低:提供了类SQL查询语言HQL(简单,容易上手),避免了直接写MapReduce,上手快,减少开发人员的学习成本。
2.可扩展性好:为超大数据集设计了计算/扩展能力(MR作为计算引擎,HDFS作为存储系统),Hive可以自由的扩展集群的规模,一般情况下不需要重启服务。
3.适合做离线分析处理(OLAP):Hive的执行 延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合。
4.延展性好:Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
1. hive的HQL表达能力有限
- 基于模板实现,所以不够智能化,很多复杂的计算无法支持。如迭代式计算
- 数据挖掘方面,由于MapReduce数据处理流程的限制,效率更高的算法却无法实现
2. hive的效率比较低
- hive自动生成的mapreduce作业,需要消耗非常多的资源
- hive调优比较困难,粒度较粗,对小数据量没有优势
所以hive通常适用于大数据的OLAP(On-Line Analytical Processing联机分析处理)场景,做一些面向分析,允许有延迟的数据挖掘工作。并且结合其他组件也可以用来做一些数据清洗之类的简单数据处理工作。
hive是基于Hadoop的,所以hive的可扩展性与Hadoop的可扩展性是一致的。而Hadoop相比于传统数据库:
扩展能力强。Hadoop支持将不同配置的机器一起组成庞大的集群,而关系型数据库做不到这一点。
数据处理能力强。当数据量非常大时,关系型数据库虽然可以用分库分表等方式进行扩展,但数据承载能力相当有限,并且数据量大了之后,性能下降明显。而基于Hadoop的大数据体系承载海量数据就轻松很多。数据量增大对整体性能的影响十分有限。
MySQL |
Hive |
|
查询语言 |
SQL |
HQL |
存储 |
存储在自己的系统中 |
HDFS |
数据格式 |
系统定义格式 |
可自定义 |
数据更新 |
可以CRUD |
不支持数据的改写和添加 |
执行/索引 |
excutor执行引擎 |
MapReduce |
使用环境 |
无限制 |
Hadoop |
延迟性 |
低延迟 |
高延迟 |
数据规模 |
小数据量 |
大数据量 |
可扩展性 |
低 |
高 |
语法:
create database [if not exists] database_name
[comment database_comment] // 注释
[location hdfs_path] // 指定数据库在hdfs上存储的路径
[with dbproperties (property_name=property_valus , ...)]; // 给数据库添加键值对参数
注:若不指定路径,默认在/opt/soft/hive312/warehouse下
案例:
create database db_hive;
create database db_hive2 with dbproperties ('create_Date'='2023-02-21');
语法:
show database [like 'identifier_with_wildcards'];
案例:
hive (default)> show databases like 'db_hive*';
OK
database_name
db_hive1
db_hive2
Time taken: 0.527 seconds, Fetched: 2 row(s)
语法:
describe database [extended] db_name;
案例:
① 查看基本信息
hive (default)> describe database db_hive2;
OK
db_name comment location owner_name owner_type parameters
db_hive2 hdfs://hadoop02:9000/opt/soft/hive312/warehouse/db_hive2.db root USER
Time taken: 0.454 seconds, Fetched: 1 row(s)
② 查看更多信息
hive (default)> describe database db_hive2;
OK
db_name comment location owner_name owner_type parameters
db_hive2 hdfs://hadoop02:9000/opt/soft/hive312/warehouse/db_hive2.db root USER
Time taken: 0.454 seconds, Fetched: 1 row(s)
hive (default)> describe database extended db_hive2;
OK
db_name comment location owner_name owner_type parameters
db_hive2 hdfs://hadoop02:9000/opt/soft/hive312/warehouse/db_hive2.db root USE{create_Date=2023-02-21}
Time taken: 0.094 seconds, Fetched: 1 row(s)
语法:
——修改dbproperties
alter database database_name set dbproperties (property_name=property_value, ...);
——修改location
alter database database_name set location hdfs_path;
——修改owner user
alter database database_name set owner user user_name;
案例:
① 修改dbproperties
hive (default)> alter database db_hive2 set dbproperties('create_Date'='2022-02-22');
OK
Time taken: 0.458 seconds
语法:
drop database [if exists] database_name [restrict | cascade];
注:restrict严格模式,若数据库不为空,则会删除失败,默认为该模式。
cascade级联模式,若数据库不为空,则会将数据库中的表一并删除。
案例:
① 删除空数据库
hive (default)> drop database db_hive2;
② 删除非空数据库
hive (default)> drop database db_hive2 cascade;
语法:
use database_name;
语法:
create [ temporary] [ external] table [ if not exists]
[db_name.]table_name
[(col_name data_type [ comment col_comment], ...)]
[ comment table_comment]
[ partitioned by (col_name data_type [ comment col_comment], ...)]
[ clustered by (col_name, col_name, ...)
[ sorted by (col_name, col_name, ...)]
[ row format row_format]
[ stored as file_format]
[ location hdfs_path]
[ tblproperties (proeprty_name=property_value, ...)]
① temporary
临时表,该表只在当前会话可见,会话结束,表会被删除。
② external
外部表,与之对应的时内部表。内部表一位置hive会完全接管该表,包括元数据和HDFS中的数据。而外部表意味着hive只接管元数据,而不完全接管HDFS中的数据。
③ data_type
hive中的字段类型可以分为基本数据类型和复杂数据类型。
Hive |
说明 |
定义 |
tinyint |
1byte 有符号整数 |
|
smallint |
2byte 有符号整数 |
|
int |
4byte 有符号整数 |
|
bigint |
8byte 有符号整数 |
|
boolean |
||
float |
单精度浮点数 |
|
double |
双精度浮点数 |
|
decimal |
十进制精确数字类型 |
decimal(16,2) |
varchar |
字符序列,需指定最大长度 最大长度范围 [1,65535] |
varchar(32) |
string |
字符串,无需指定最大长度 |
|
timestamp |
时间类型 |
|
binary |
二进制数据 |
类型 |
说明 |
定义 |
取值 |
array |
数组是一组相同类型的值的集合 |
array |
arr[0] |
map |
map时一组相同类型的键-值对集合 |
map |
map['key'] |
struct |
结构体由多个属性组成,每个属性都有自己的属性名和数组类型 |
struct |
struct.id |
④ partitioned by
创建分区表
⑤ clustered by ... sorted by ... into ...buckets
创建分桶表
⑥ row format
delimited
fields terminated by:列分隔符
collection items terminated by:map、struct和array中每个元素之间的分隔符
map keys terminated by:map中的key和value的分隔符
lines terminated by:行分隔符
⑦ stored as
指定文件格式,常用的文件格式由,textfile,sequence file,orc file,parquet file等待
⑧ location
指定表所对应的HDFS路径。默认值为${hive.metastore.warehouse.dir}/db_name.db/table_name
⑨ tblproperties
用于配置表的一些KV键值对参数
案例:
-- 1,xiaoming1,lol-book-movie,beijing:bdqn-nanjing:zhongbo
-- 2,xiaoming2,lol-book-movie,beijing:bdqn-nanjing:zhongbo
-- 3,xiaoming3,lol-book-movie,beijing:bdqn-nanjing:zhongbo
-- 4,xiaoming4,lol-book-movie,beijing:bdqn-nanjing:zhongbo
-- 5,xiaoming5,lol-movie,beijing:bdqn-nanjing:zhongbo
-- 6,xiaoming6,book-movie,beijing:bdqn-nanjing:zhongbo
-- 7,xiaoming7,lol-book,beijing:bdqn-nanjing:zhongbo
-- 8,xiaoming8,lol-book,beijing:bdqn-nanjing:zhongbo
-- 9,xiaoming9,lol-book-movie,beijing:bdqn-nanjing:zhongbo
-- 10,xiaoming10,lol,beijing:bdqn
create table if not exists student(
id int,
name string,
likes array,
address map
)
row format delimited
fields terminated by ","
collection items terminated by "-"
map keys terminated by ":"
lines terminated by "\n";
# 查询数据
select likes[0],address["beijing"] from student;
# KV查询
select address["beijing"] from student; // 根据key查询value
select map_keys[address] from student; // 查询所有的key值
select map_keys[address][0] from student;
select map_values[address] from student; // 查询所有的value值
select map_values[address][0] from student;
该语法允许用户利用select查询语句返回的结果,直接建表。表的结构和查询语句的结构保持一致,且保证包含select查询语句返回的内容。
create [temporary] [external] table [if not exists] table_name
[comment table_comment]
[row format row_format]
[stored as file_format]
[location hdfs_path]
[tblproperties (proeprty_name=property_value, ...)]
[ as select_statement]
CREATE TABLE ctas_employee as SELECT * FROM employee;
CREATE TABLE cte_employee AS
WITH
r1 AS (SELECT name FROM r2 WHERE name = 'Michael'),
r2 AS (SELECT name FROM employee WHERE sex_age.sex= 'Male'),
r3 AS (SELECT name FROM employee WHERE sex_age.sex= 'Female')
SELECT * FROM r1 UNION ALL SELECT * FROM r3;
允许用户复刻一张已经存在的表结构。与CTAS不同,该语法创建出来的表不包含数据
create [temporary] [external] table [if not exists] table_name
[db_name.]table_name
[ like exist_table_name]
[row format row_format]
[stored as file_format]
[location hdfs_path]
[tblproperties (proeprty_name=property_value, ...)]
CREATE TABLE employee_like LIKE employee;
语法:
show tables [ in database_name ] like [ 'iderntifier_with_wildcards' ];
案例:
show tables like 'stu*';
语法:
describe [ extended | formatted ] [ db_name ].table_name
extended:展示详细信息
formatted:对详细信息进行格式化的展示
案例:
desc student; // 查看基本信息
desc formatted student; // 查看更多信息
语法:
alter table table_name rename to new_table_name
案例:
alter table student rename to stu;
语法:
① 增加列:允许用户增加新的列,新增列位于末尾
alter table table_name add columns (col_name data_type [ comment col_comment ], ... )
② 更新列:允许用户修改指定列的列名、数据类型、注释信息、在表中的位置
alter table table_name change [ columns ] col_old_name col_new_name column_type [ comment col_comment ] [ first | after column_name ]
③ 替换列:允许用户用新的列集替换原有的全部列
alter table table_name replace columns (col_name data_type [ comment col_comment ], ... )
案例:
alter table student add columns(age int); // 添加列
alter table student change column age ages double; // 更新列
alter table student replace columns(id int, name string); // 替换列
语法:
drop table [ if exists ] table_name;
案例:
drop table stu;
语法:
truncate [ table ] table_name
注意:truncate只能清空管理表,不能删除外部表中数据。
案例:
truncate table stu;
语法:
load data [ local ] inpath 'filepath' [ overwrite ] into table tablename [ patrition ( partcol1=val1, partcol2=val2 ...) ]
local:从本地加载数据到hive表。否则从HDFS加载数据到hive表
overwrite:覆盖表中已有数据,否则表示追加
partition:上传到指定分区
案例:
# 上传本地数据到指定分区,覆盖表中原有数据
load data local inpath '/opt/stufile/student.txt' overwrite into table student2 partition (age=20)
语法:
insert ( into | overwrite ) table tablename [ partition ( partcol1=val1 , partcol2=val2 ...) ]
select_statement;
案例:
# 将student表中的数据插入到stu_new中
insert into table stu_new
select * from student;
语法:
insert ( into | overwrite ) table tablename [ partition ( partcol1=val1 , partcol2=val2 ...) ]
values values_row [ , values_row ... ]
案例:
insert into table stu_new
values(1,'zhangsan'),(2,'zhaosi');
语法:
insert overwrite [ local ] directory 'directory' [ row format row_format ] [ stored as file_format ] select_statement;
案例:
insert overwrite local directory '/opt/stufile/student_new.txt'
select * from student;
数据会导出到本地的目录文件下。
export和import可用于两个hive实例之间的数据迁移。
export将表的数据和元数据信息一并导出到HDFS路径。
import将export导出的内容导入到hive。
语法:
——导出
export table tablename to 'export_target_path'
——导入
import [ external ] table new_or_origunal_tablename from 'source_path' [ location 'import_target_path' ]
案例:
# 导出
export table student to '/new';
# 导入,默认路径在hive(default)下
import table student02 from '/new';
select [ all | distinct] select_expr, select_expr, ...
from table_reference
[ where where_condition ]
[ group by col_list ]
[ having col_list ]
[ order by col_list ]
[ cluster by col_list | [ distribute by col_list ] [ sort by col_list ] ]
[ limit number ]
基本查询语句与SQL语句类似。
No |
运算关系 |
符号 |
举例 |
返回值 |
1 |
等值 |
= |
select 1 from stu where 1=1; |
1 |
2 |
不等值 |
<> |
select 1 from stu where 1 <> 2; |
1 |
3 |
小于 |
< |
select 1 from stu where 1 < 2; |
1 |
4 |
小于等于 |
<= |
select 1 from stu where 1 <= 2; |
1 |
5 |
大于 |
> |
select 1 from stul where 2 > 1; |
1 |
6 |
大于等于 |
>= |
select 1 from stul where 2 >= 1; |
1 |
7 |
空值判断 |
is null |
select 1 from stu where null is null; |
1 |
8 |
非空判断 |
is not null |
select 1 from stu where 1 is not null; |
1 |
9 |
like比较 |
like |
select 1 from stu where zs like 'z%' | 'z_'; |
1 |
10 |
正则表达式 |
regexp |
函数 |
释义 |
count(*) |
统计所有行数,包括null值 |
count(某列) |
该列一共右多少行,不包括null值 |
max() |
求最大值,不包含null |
min() |
求最小值,不包含null |
sum() |
求和,不包含null |
avg() |
求平均值,不包含null |
group by语句通常和聚合函数一起使用。按照一个或多个队列结果进行分组,然后对每个组执行聚合操作。
# 查询分组字段有几个值
select count(*) from emp group by job;
where是在group by之前执行的,分组函数是在group by以后执行的,分组函数无法用在where后面。所以需要使用having语句对分组之后的数据进行再次过滤。
select count(*) from emp group by job having job like '人事%';
hive支持通常的sql join语句。但是有些版本只支持等值连接,不支持非等值连接。
# 等值连接
select * from emp join dept on emp.deptno=dept.deptno;
# 不等值连接
select * from emp join dept on emp.deptno>dept.deptno;
只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
select
e.empno,e.ename,d.deptno
from emp e
join dept d
on e.deptno=d.deptno;
join操作符左边表中符合where子句的所有记录将会被返回。
select
e.empno,e.ename,d.deptno
from emp e
left join dept d
on e.deptno=d.deptno;
join操作符右边表中符合where子句的所有记录将会被返回。
select
e.empno,e.ename,d.deptno
from emp e
right join dept d
on e.deptno=d.deptno;
返回表中符合where语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用null值替代。
select
e.empno,e.ename,d.deptno
from emp e
full join dept d
on e.deptno=d.deptno;
连接n个表,至少需要n-1个连接条件。如连接三个表,至少需要两个连接条件。
select
e.ename,d.dname,l.loc_name
from emp e
join dept d
on e.deptno=d.deptno
join location l
on d.loc=l.loc;
笛卡尔积会在下面条件下产生:
省略连接条件
连接条件无效
所有表中的所有行互相连接
union和union all都是上下拼接sql的结果。join是左右关联,union和union all是上下拼接,union去重,union all不去重。
union和union all在上下拼接sql结果时右两个要求:
两个sql的结果,列的个数必须相同
两个sql的结果,上下所对应列的类型必须一致
select
empno,ename,job,sal,deptno
from emp
where deptno=30
union
select
empno,ename,job,sal,deptno
from emp
where deptno=40
order by 全局排序,只有一个reduce。
# 升序排序。默认为升序排序
select * from emp order by sal asc;
# 降序排序
select * from emp order by sal desc;
hive sql执行过程:
通过一个mapreduce来完成计算,map可能会有多个。如果文件过大,mr在读取文件的时候可能会对文件进行切片。由于order by是全局排序,即对表里所有的数据进行排序,所以在我们使用的时候,指定reduce的个数是没有用的,必须把所有的数据都放到一个reduce里面才能保障全局有序。
而如果指定reduce个数大于一个,我们只能保证每一个reduce里的数据是有序的,无法做到全局有序。而如果数据量非常大,使用order by进行排序,所有语句都会进入到一个reduce中,影响运行效率。
一般会配合limit语句进行优化。使用limit语句优化的reduce端同样只有一个,但是在map端会进行优化。如:有10,000条数据,使用limit 100之后,两个map端只会返回前100行的数据。而reduce只需要在两个map各自的100条数据里筛选出前100条数据,不用再处理全部数据。
对于大规模数据集,order by的效率非常低下(只有一个reduce)。在很多情况下不需要全局排序,此时可以使用sort by。
sort by为每一个reduce产生一个排序文件。每个reduce内部进行排序,对全局结果集来说不是排序。
设置reduce个数
set mapreduce.job.reduces=3;
查看设置reduce个数
set mapreduce.job.reduces;
根据编号查询学生信息
select * from student sort by id;
指定mapreduce的分区字段。map到reduce端需要进行shuffle,即根据指定字段进行hash分区,distribude by就是指定分区字段。
distribute by类似mapreduce中partition(自定义分区)进行分区,结合sort by使用。对于distribute by一定要分配多reduce进行处理,否则无法看到效果。
select * from student
distribute by name
sort by id desc;
当distribude by 和sort by 字段相同时,可以使用cluster by 字段。同时具有distrubude by+sort by功能,但是只能升序排序,不能指定排序规则为asc或desc。
order by 是全局排序,无论设置reduce的个数为多少,都只有一个reduce,效率较低。
sort by是区内排序。单独使用sort by的时候,随机划分数据所在区,往往和distribute by连用。
distribute by使用字段来帮助分区,通过sort by来排序。
distribute by和sort by字段相同,且都是升序是,可以用cluster by来代替。