目錄
Hive
Hive是基於Apache Hadoop的數據倉庫基礎架構,可以將結構化的數據文件映射爲一張數據庫表,並提供完整的sql查詢功能,再將sql語句轉換爲MapReduce任務進行運行。 其優點是學習成本低,可以通過類SQL語句快速實現簡單的MapReduce統計。但是Hive不適用於在線數據處理,它最適用於傳統的數據倉庫任務。
上圖是Hive與Hadoop1.x的工作流程示意圖。
Hive是構建在Hadoop之上的數據倉庫:
數據存放在HDFS上,但是元數據一般存放在Mysql中。
執行引擎可以使用 MapReduce、Spark、Tez 等
運行在Yarn上:Hive通過執行引擎與Hadoop聯繫,提交任務給Yarn(JOB Tracker),存放數據在HDFS。
Hive 操作起來和關係型數據庫很相像,HQL也是類SQL語言,但是還是有一些區別的:
- Hive是讀時模式:其實是讀時校驗模式,在保存表數據時不對數據進行校驗,而是在讀數據時校驗,不符合格式的數據設置爲NULL。
關係型數據庫是寫時模式:不符合格式的數據無法寫入數據庫。
這兩種區別是根據兩者作用不同而設計的:Hive存儲的是海量數據,讀時模式可以使加載數據的速度很快,但是需要查詢,處理數據時慢很多,所以適用於離線處理;而關係型數據庫在寫時模式時會對列進行索引處理,對數據進行壓縮,因此加載數據會很慢,但是隻要加載好數據,查詢起來會很快。 - 關係數據庫可以對某一行或者多行的數據進行更新、刪除操作。但是Hive中不支持對具體行的操作,Hive對數據的操作只支持覆蓋原數據和追加數據。
- 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;
注意點:
- 最後一個字段(如果是多級,最後幾個字段挨個寫入)
- 嚴格模式關掉(先按照上述方法創建、導入,有提示嚴格模式,按照指令操作)
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操作模式
- 交互式命令行
- hive - e "use d6_hive;select * from emp "
- 腳本操作 再用 sh xxx.sh執行操作
- hive -f abc.sql 執行文件