Hive_01 Hive基础

Hive

Hive是基于Apache Hadoop的数据仓库基础架构,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,再将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计。但是Hive不适用于在线数据处理,它最适用于传统的数据仓库任务。
Hive工作流程图
上图是Hive与Hadoop1.x的工作流程示意图。
Hive是构建在Hadoop之上的数据仓库:
数据存放在HDFS上,但是元数据一般存放在Mysql中。
执行引擎可以使用 MapReduce、Spark、Tez 等
运行在Yarn上:Hive通过执行引擎与Hadoop联系,提交任务给Yarn(JOB Tracker),存放数据在HDFS。

Hive 操作起来和关系型数据库很相像,HQL也是类SQL语言,但是还是有一些区别的:

  1. Hive是读时模式:其实是读时校验模式,在保存表数据时不对数据进行校验,而是在读数据时校验,不符合格式的数据设置为NULL。
    关系型数据库是写时模式:不符合格式的数据无法写入数据库。
    这两种区别是根据两者作用不同而设计的:Hive存储的是海量数据,读时模式可以使加载数据的速度很快,但是需要查询,处理数据时慢很多,所以适用于离线处理;而关系型数据库在写时模式时会对列进行索引处理,对数据进行压缩,因此加载数据会很慢,但是只要加载好数据,查询起来会很快。
  2. 关系数据库可以对某一行或者多行的数据进行更新、删除操作。但是Hive中不支持对具体行的操作,Hive对数据的操作只支持覆盖原数据和追加数据。
  3. Hive是支持索引的,但是和关系型数据库索引不太相同,而且实际效率上差强人意,一般不使用。

Hive和关系型数据库的这些区别,其实都是根据两者作用不同而设计的:
Hive更多的用在多任务节点的场景下,快速地全表扫描大规模数据,所以一般不会针对个别的行来执行查询、更新、删除操作。索引本身是用空间换时间,但Hive需要操作的数据量大,索引会消耗更多的资源。

Hive DDL

Hive的数据库

Hive 是由 Database/Table/Partition 组成 ,Hive中的这些层次都是对应于HDFS上的一个目录或者文件。
create database hive01;
默认会把hive01数据库创建在 hdfs://hadoop001:9000/user/hive/warehouse/hive01.db
(可以通过desc database+数据库名 来查询数据库的具体信息)
其中 hdfs://hadoop001:9000 为 HDFS 的目录 可以在hadoop下配置。
user/hive/warehouse/ 为默认的hive存储在HDFS上的目录,可以修改hive.metastore.warehouse.dir:
set hive.metastore.warehouse.dir=xxx;
或者在 hive-site.xml 上通过增加键值对配置来修改。
hive.db是指创建的database,和在default数据库上创建的表作为划分(在default数据库上创建的表默认的存储的地址也是/user/hive/warehouse/)
查看mysql中的关于Hive的元数据:
use gru;(之前在hive-site中配置的 javax.jdo.option.ConnectionURL)
select * from dbs \G ; (\G表示格式化输出)

Hive表

Hive表的操作

CREATE [TEMPORARY] [EXTERNAL] TABLE table_name
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]<font></font>
[ROW FORMAT row_format] <font></font>    //例如:ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
[LOCATION hdfs_path]<font></font>

创建的表以 tab 键作为列与列的分割,而行与行的分隔默认的就可以

也可以通过 拷贝表结构的方法:
create table emp2 like emp; (已有emp表)
拷贝表结构和表数据:
create table emp3 as selected * from emp;

可以通过 desc formatted emp3; 的方式查看表的详细信息
小窍门:show create table emp3;

内部表和外部表

内部表、外部表最本质的不同在于:Hive拥有内部表的数据,但不拥有外部表的数据。外部表数据由HDFS管理,所以外部表的数据最好由自己location。
删除内部表会直接删除元数据及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE table_name;)
所以内部表适用于自己处理,不共享的情况;外部表由于数据存储在HDFS上,所以适合数据的共享。

Hive DML

加载数据

LOAD

Hive 中加载数据 大多数时候都会用到 LOAD 加载 :

LOAD DATA [LOCAL] INPATH 'FILEPATH' [OVERWRITE] INTO TABLE table_name
LOCAL 表示 文件是在 linux 本地的 ,没有 LOCAL 表示文件实在 HDFS 上的
OVERWRITE 表示 加载的文件是 覆盖原文件 ,没有 OVERWRITE 表示 只是追加 。  

LOAD DATA INPATH ‘xxxx’ OVERWRITE INTO TABLE table_name;
会把 HDFS 上的文件 转移到 Hive中对应数据库的表的文件夹下,原先路径下的文件就不在了。

load 是不走 mapreduce 的,但是insert into table table_name values(…);
是要走mapreduce的

INSERT 从查询中将数据插入Hive表中

INSERT OVERWRITE TABLE tablename select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 select_statement1 FROM from_statement;

会判断 select_statement1 的数据 是否满足列数的要求。
需要跑MapReduce的。

INSERT 插入值到表中

INSERT INTO TABLE table_name VALUES (....) , (....) ; 

每个括号代表每一行,且每行必须为表中的每个列提供值。
只能插入个别行,所以不适合海量数据,所以在Hive中应用很少。
并且效率低下,需要执行Mapreduce,且会产生小文件,是生产上忌讳的。

INSERT 从查询中将Hive数据写入HDFS/本地上

INSERT OVERWRITE [LOCAL] DIRECTORY 
'/home/hadoop/tmp/d6/emptmp'
row format dilimited fields teminated by ','
select empno,empname from emp 

之后可以使用 Sqoop 代替

也需要跑MapReduce

select 查询

select * from xxx where = (> < >= <=) limit x
select * from xxx between xx and xx    是左闭右闭的
select * from xxx where name in ('b','a')

聚合函数

聚合函数特点是 多进一出
max min sum count avg

全局的聚合
select max(sal) min(sal) sum(sal) avg(sal) count(1) from emp;
各个部门的平均工资
select deptno,avg(sal) from emp group by deptno;

如果有GROUP BY 的语句,在SELECT中的字段,要么出现在 GROUP BY 中 ,要么出现在聚合函数中。
GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前。HAVING语句必须在ORDER BY子句之后。
where先执行,再groupby分组;
groupby先分组,having在执行。

case when then

select ename,sal, 
case 
when sal >1 and sal <= 1000 then 'lower'
when sal>1000 and sal <=2000 then 'middle'
else 'higher' end
from emp

在报表中常见。速度很快,不用走MapReduce

Hive 函数

内置函数: build-in 内置
外置函数:UDF 用户自定义函数

内置函数

查找内置函数:show functions;
查看函数信息:desc functions 函数名;
查看函数详细信息(有例子):desc function extended 函数名

创建一张伪表
create table dual(x string);
insert into table values('');

用 abs()函数
select abs(10) from dual;
10
select abs(-10) from dual;
10

用upper() lower() 将一串字符串 变全部大写/小写
将 ename 里的字符串 全部变成小写的
select ename,lower(ename) from emp;

时间相关的内置函数

查看当前日期
select current_date from dual;
查看当前时间
select current_timestamp from dual;
查看时间戳
select unix_timestamp() from dual;
把字符串形式的时间转为时间戳
select unix_timestamp("2019-03-06 22:20:32")
把一般形式的字符串形式的时间转为时间戳
select unix_timestamp("20190306222032","yyyyMMddHHmmss")
字符串形式时间转化为date类型
select to_date("2019-03-06 22:20:32") from dual; 
select year("2019-03-06 22:20:32") from dual;
将日期加减:
select date_add("2019-03-06 22:20:32",10)from dual;

数据相关的操作

select round(5.6) from dual;  四舍五入
select ceil(5.6) from dual;   进一
select ceil(5.4) from dual;   
select floor(5.6) from dual;  取整

字符串相关

截取字符串:substr(str, pos[, len])     pos开始位置,len是长度
select substr("abcdefg",2)from dual;  
合字符串
select concat("ab","cd") from dual;
select concat_wd("------","ab","cd") from dual;以----为分隔符,输出ab-----cd
拆
select split("192.168.1.1:8020",":") from dual; 
["192.168.1.1","8020"]    split 拆分后的每一行是数组
select split("192.168.1.1:8020","\\.") from dual;      这里.是特殊字符 需要\\转义
["hello","world","hello"]
["hello","world","welcome"]
["hello"]
===> 行转列    列转行
selcect explode(split(sentence,"\t")) from hive_wc;  
(explode(a) 把一个数组a,拆分成多行,每个元素占一行)
explode 行转列 将数组中的值 转成多行数据 每个元素占一行

WordCount例子

create table wc(setence string) ;
load data local inpath 'xxx' into table wc;
select word,count(1) c from
(select explode(split(setence,"\\t")) as word from wc )t
group by word order by c desc;

分区表

分区表可以明显减少数据的读写操作,其实质就是对应hdfs文件系统上的的独立的目录。Hive的一个分区名对应一个目录名,子分区名就是子目录名,并不是一个实际字段。

show partitions table_name; //查看表里的分区有哪些
/user/hive/warehouse/emp/d=20190808/.....
/user/hive/warehouse/emp/d=20190809/.....
select .... from table where d='20190808'
使用时 可以直接筛选出来分区表,而并不用遍历整个table

静态分区

静态分区,由于分区的值是确定的,每次录入数据需要将数据输入到确定的分区中(分区是用key=value形式来定的)

// 建表
create table order_partition(
order_no string,
event_time string
)
PARTITIONED BY(event_month string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
// 录入数据
load data local inpath '/home/hadoop/data/order.txt'
overwrite into table order_partition
PARTITION  (event_month='2014-05'); 

除了直接在建表的时候建分区表,也可以后期创建分区表,导入数据进入。但是如果仅仅自己手工创建文件夹去作为分区表的话,Hive是不会识别出来自己手工建的分区表,因为Hive不仅仅是HDFS上的文件夹,还有元数据信息存储在与之关联的关系型数据库中,仅仅在表文件夹下创建文件夹,Hive是不会将元数据信息录入关系型数据库中,所以需要用指令去创建:

ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION 
(key=value);

多层静态分区:有时数据量很大时,一级分区已经满足不了需求,就需要多级分区

// 创建多级分区表
create table order_mulit_partition(
order_no string,
event_time string
)
PARTITIONED BY(event_month string, step string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
// 加载数据
load data local inpath '/home/hadoop/data/order.txt' overwrite into table order_mulit_partition
PARTITION  (event_month='2014-05', step='1');
// 查询:最好到最底层查询
select * from table_name where 
event_month='2014-05' and step='1';

动态分区

动态分区由于分区的值不是固定的,一次可以插入不同分区的数据,不像静态分区那样,每次插入一个分区的数据就需要跑map

// 动态分区表的创建和静态分区一样
CREATE TABLE `emp_dynamic_partition`(
  `empno` int, 
  `ename` string, 
  `job` string, 
  `mgr` int, 
  `hiredate` string, 
  `sal` double, 
  `comm` double)
partitioned by(deptno int)  
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
// 加载数据时,只用写分区变量,分区值不需要写;
   并且分区变量必须写到select的最后
insert into table emp_dynamic_partition PARTITION (deptno) 
select empno,ename,job,mgr,hired`ate,sal,comm,deptno from emp;

注意点:

  1. 最后一个字段(如果是多级,最后几个字段挨个写入)
  2. 严格模式关掉(先按照上述方法创建、导入,有提示严格模式,按照指令操作)

Hive中的复杂数据类型

Hive中的字段可以是复杂数据类型:Array,Map,Struct

Array数组

// 创建表
create table hive_array(
name string,
work_locations array<string>
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'  //列的分隔符
COLLECTION ITEMS TERMINATED BY ',';    //集合内的元素分隔符
// 导入数据	
load data local inpath '/home/hadoop/data/hive_array.txt' 
overwrite into table hive_array;
// 从表中取Array数组中的数据
select name,work_locations[0] from hive_array;   //按照数组下标来选取
select name,size(work_locations) from hive_array;  //读取数组的长度
select * from hive_array where array_contains(work_locations,'tianjin'); //查看哪些行的数据信息包含xxx

Map

// 建表
create table hive_map(
id int,
name string,
members map<string,string>,
age int
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '#'
MAP KEYS TERMINATED BY ':';    //顺序需要注意
// 导入信息
load data local inpath '/home/hadoop/data/hive_map.txt' 
overwrite into table hive_map;
// 从Map中取值
select id,name,age,members['father'] from hive_map; //Map中,根据Key值来取Value值
select id,name,age,map_keys(members) from hive_map;
select id,name,age,map_values(members) from hive_map;
select id,name,age,size(members) from hive_map;

Struct 结构体

// 假定数据信息为:192.168.1.1#zhangsan:40 
// 建表
create table hive_struct(
ip string,
userinfo struct<name:string,age:int>
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '#'
COLLECTION ITEMS TERMINATED BY ':';
	
load data local inpath '/home/hadoop/data/hive_struct.txt' 
overwrite into table hive_struct;

select userinfo.name userinfo.age from hive_struct;

Hive实例

create table hive_wc(sentence string);
load data local inpath ' ' into table hive_wc;
select word,count(1) c 
from 
(select explode(split(sentence,'\t'))as word 
from hive_wc)as t 
group by word
order by c desc;

这个例子跑了两个MapReduce
一个是 group by 一个是 orderby

Hive操作模式

  1. 交互式命令行
  2. hive - e "use d6_hive;select * from emp "
  3. 脚本操作 再用 sh xxx.sh执行操作
  4. hive -f abc.sql 执行文件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章