1.數據倉庫
1)數據倉庫的基本概念
數據倉庫的英文名稱為Data Warehouse,可簡寫為DW或DWH。
數據倉庫的目的是構建面相分析的集成化數據環境,為企業提供決策支持(Decision Support)。它出於分析性報告和決策支持的目的而創建。
數據倉庫本身並不“生產”任何數據,同時自身也不需要“消費”任何數據,數據源於外部,並且開放給外部應用,這也是為什么叫“倉庫”,而不是“工廠”的原因。
2)數據倉庫的主要特征
數據倉庫是面向主題的(Subject-Oriented)、集成的(Integrated)、非易失的(Non-Volatile)和時變的(Time-Variant)數據集合,用以支持管理決策。
3)數據倉庫與數據庫的區別
數據庫與數據倉庫的區別實際講的是OLTP與OLAP的區別。
操作型處理,叫聯機事務處理OLTP(On-Line Transaction Processing),也可以稱面向交易的處理系統,他是針對具體業務在數據庫聯機的日常操作,通常對少數記錄進行查詢、修改。用戶較為關心操作的響應時間、數據的安全性、完整性、和並發支持的用戶數等問題。傳統的數據庫系統作為數據管理的主要手段,主要用於操作型處理OLTP。
分析型處理,叫聯機分析處理OLAP(On-Line Analytical Processing),一般針對某些主題的歷史數據進行分析,支持管理決策。
數據倉庫的出現並不是要取代數據庫。
數據庫是面向事務的設計,數據倉庫是面向主題設計的。
數據庫一般存儲業務數據,數據倉庫存儲的一般是歷史數據。
數據庫設計師盡量避免冗余,一般針對某一業務應用進行設計,比如一張簡單的User表,記錄用戶名,密碼等簡單數據即可,符合業務應用,但是不符合分析;數據倉庫在設計上是有意引入冗余,依照分析需求,分析維度,分析指標進行設計。
數據庫是為捕獲數據而設計,數據倉庫是為分析數據而設計。
以銀行業務為例。數據庫是事務系統的數據平台,客戶在銀行做的每筆交易都會寫入數據庫,被記錄下來,這里,可以簡單地理解為數據庫記賬。數據倉庫是分析系統的數據平台,它從事務系統獲取數據,並做匯總、加工,為決策者提供決策依據。比如某銀行分行一個月發生多少交易,該分行當前存款余額是多少。如果存款又多,消費交易又多,那么該地區就有必要設立ATM。
顯然,銀行的交易量是巨大的,通常以百萬甚至千萬次來計算。事務系統是實時的,這就要求時效性,客戶存一筆需要幾十秒是無法忍受的,這就要求數據庫智能存儲很短一段時間的數據。而分析系統是事后的,它要提供關注時間段內所有的有效數據。這些數據是海量的,匯總計算起來也要慢一些,但是只要提供有效的分析數據就達到目的了。
數據倉庫,是數據庫大量存在的情況下,為了進一步挖掘數據資源、為了決策需要而產生的,它絕不是所謂的“大型數據庫”。
4)數據倉庫的分層架構
按照數據流入流出的過程,數據倉庫結構可分為三層——源數據層、數據倉庫層、數據應用層。
數據倉庫的數據源於不同的源數據,並提供多樣的數據應用,數據自下而上流入數據倉庫后向上層開放應用,而數據倉庫只是中間集成化數據管理的一個平台。
源數據層(ODS):此層數據無任何更改,直接沿用外圍系統數據結構和數據,不對外開放;為臨時存儲層,是接口數據的臨時存儲區域,為后一步數據處理做准備。
數據倉庫層(DW):也成為細節層,DW層的數據應該是一致的、准確的、干凈的數據,即對源系統數據進行了清洗(去除了雜質)后的數據。
數據應用層(DA或APP):前端應用直接讀取的數據源;根據報表、專題分析需求而計算生成的數據。
數據倉庫從各數據源獲取數據及在數據倉庫內的數據轉換和里流動都可以認為是ETL(抽取Extra,轉化Transfer,裝載:oad)的過程,ETL是數據倉庫的流水線,也可以認為是數據倉庫的血液,它維系着數據倉庫中數據的新城代謝,而數據倉庫日常的管理和維護工作的大部分精力就是保持ETL的正常和穩定。
為什么要對數據倉庫分層?
用空間換時間,通過大量的預處理來提升應用系統的用戶體驗(效率),因此數據倉庫會存在大量的冗余數據;不分層的話,如果源業務數據規則發生變化將會影響整個數據清洗過程,工作量巨大。
通過把數據分層管理可以簡化數據的清洗過程,因為把原來一步的工作分到了多個步驟去完成,相當於把一個復雜的工作拆成了多個簡單的工作,把一個大的黑盒變成了一個白盒,每一層的處理邏輯都相對簡單和容易理解,這樣我們比較容易保證每一個步驟的正確性,當數據發生錯誤的時候,往往我們只需局部調整某個步驟即可。
2.Hive
1)Hive的概念
hive是基於hadoop的一個數據倉庫工具
可以將結構化的數據文件映射為一張數據庫表,並提供類似SQL查詢功能
其本質是將SQL轉換為MapReduce的任務進行運算,底層有HDFS來提供數據的存儲支持,說白了hive可以理解為一個將SQL轉換為MapReduce任務的工具,甚至更進一步可以說hive就是一個MapReduce的客戶端
2)Hive與數據庫的區別
Hive具有SQL數據庫的外表,但是應用場景完全不同。
Hive只適合用來做海量離線數據統計分析,也就是數據倉庫。
3)Hive的優缺點
優點:
操作接口采用類SQL語法,提供快速開發的能力(簡單容易上手)。
避免了去寫MapReduce,減少開發人員的學習成本。
Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。
缺點:
Hive的查詢延遲嚴重
Hive不支持事務
4)Hive架構原理
①用戶接口:Client
CLI(hive shell)
JDBC/ODBC(java訪問hive)
WEBUI(瀏覽器訪問hive)
②元數據:Metastore
元數據包括:表名、表所屬的數據庫(默認default)、表的擁有者、列/分區字段、表的類型(內部表或外部表)、表的數據所在目錄等;
默認儲存在自帶的derby數據庫,推薦使用MySQL存儲Metastore
③Hadoop集群
使用HDFS進行存儲,使用MapReduce進行計算
④Driver:驅動器
解釋器(SQL Parser):將sql字符串轉換成抽象語法樹AST,對AST進行語法分析,比如表是否存在、字段是否存在、SQL語義是否有誤。
編譯器(Physical Plan):將AST編譯生成邏輯執行計划。
優化器(Query Optimizer):將邏輯執行計划進行優化。
執行器(Execution):把邏輯執行轉換成可以運行的物理計划。對於hive來說默認就是Mapreduce任務
3.Hive的交互方式
使用hive前需要啟動hadoop、mysql。因為hql語句會被編譯成mr任務並提交到集群運行;hive表數據一般存在hdfs上;hive的操作過程需要訪問MySQL中存儲元數據的庫和表。
1)hive交互shell
任意路徑下運行 hive(不推薦使用)
2)Hive JDBC服務
①啟動hiveserver2服務,前台啟動或后台啟動均可
前台啟動:hive --service hiveserver2
后台啟動:nohup hive --service hiveserver2 &
②beeline連接hiveserver2
若是前台啟動需要開啟新的會話使用beeline連接hive
beeline-》!connect jdbc:hive2://node03:10000-》輸入任意用戶名密碼-》!help(查看使用幫助)
3)Hive命令
hive -e 執行hql語句
hive -f 執行hql腳本
4Hive的數據類型
1)基本數據類型
類型名稱 | 描述 | 舉例 |
---|---|---|
boolean | true/false | true |
tinyint | 1字節的有符號整數 | 1 |
smallint | 2字節的有符號整數 | 1 |
==int== | 4字節的有符號整數 | 1 |
==bigint== | 8字節的有符號整數 | 1 |
float | 4字節單精度浮點數 | 1.0 |
==double== | 8字節單精度浮點數 | 1.0 |
==string== | 字符串(不設長度) | “abc” |
varchar | 字符串(1-65355長度,超長截斷) | “abc” |
timestamp | 時間戳 | 1563157873 |
date | 日期 | 20190715 |
2)復合數據類型
類型名稱 | 描述 | 舉例 |
---|---|---|
array | 一組有序的字段,字段類型必須相同 array(元素1,元素2) | Array(1,2,3) |
map | 一組無序的鍵值對 map(k1,v1,k2,v2) | Map(‘a’,1,'b',2) |
struct | 一組命名的字段,字段類型可以不同 struct(元素1,元素2) | Struct('a',1,2,0) |
①參數說明
創建表的時候可以指定每行數據的格式,如果使用的是復合數據類型,還需要指定復合數據類型中的元素的分隔符號
row format delimited
[fields terminated by char [escaped by char]]
[collection items terminated by char]
[map keys terminated by char]
[lines terminated by char]
其中
fields terminated by char 指定每一行記錄中多字段的分隔符
collection items terminated by char 指定符合類型中多元素的分隔符
map keys terminated by char 指定map集合中每一個key,value之間的分隔符
lines terminated by char 指定每行記錄的換行符,一般有默認 就是\n
②Array類型
array中的數據為相同類型,如,array A中元素['a','b','c'],則A[1]的值為'b'
數據文件:t_array.txt(字段空格分隔)
1 zhangsan beijing,shanghai 2 lisi shanghai,tianjin
建表語法:
create table t_array( id string, name string, locations array<string> ) row format delimited fields terminated by ' ' collection items terminated by ',';
加載數據:
load data local inpath '/home/hadoop/t_array.txt' into table t_array;
查詢語法:
select id,name,locations[0],locations[1] from t_array;
③Map類型
map類型中存儲k/v類型的數據,后期可以通過指定k名稱訪問
數據文件:t_map.txt
1 name:zhangsan#age:30 2 name:lisi#age:40
建表語法:
create table t_map( id string, info map<string, string> ) row format delimited fields terminated by ' ' collection items terminated by '#' map keys terminated by ':';
加載數據:
load data local inpath '/home/hadoop/t_map.txt' into table t_map;
查詢數據:
select id, info['name'], info['age'] from t_map;
④Struct類型
可以存儲不同類型的數據。ex:c struct{a int; b int},可以通過c.a來訪問a
數據文件:t_struct.txt
1 zhangsan:30:beijing 2 lisi:40:shanghai
建表方法:
create table t_struct( id string, info struct<name:string, age:int, address:string> ) row format delimited fields terminated by ' ' collection items terminated by ':';
加載數據:
load data local inpath '/home/hadoop/t_struct.txt' into table t_struct;
查詢數據:
select id, info.name, info.age, info.address from t_struct;
5.Hive的DDL操作
1)數據庫的DDL操作
#創建數據庫
create database db_hive;
create database if not exists db_hive;#db_hive不存在才創建
#顯示所有數據庫
show databases;
#查詢所有數據庫
show databases like 'db_live*';
#查看數據庫詳情
desc database db_hive;
#查看數據庫詳細信息
desc database extended db_hive;
#切換數據庫
use db_hive;
#刪除數據庫
drop database db_hive;
drop database if exists db_hive;#數據庫存在才刪除
drop database if exists db_hive cascade;#如果數據庫中有表需要使用 cascade強制刪除
2)表的DDL操作
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] 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 [ASC|DESC], ...) INFO num_buckets BUCKETS] [ROW FORMAT row_format] row format delimited fields terminated by "分隔符" [STORED AS file_format] [LOCATION hdfs_path]
字段解釋
CREATE TABLE 創建一個指定表
EXTERNAL 創建一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),指定表的數據保在哪里
COMMENT 為表和列添加注釋
PARTITIONED BY 創建分區表
CLUSTERED BY 創建分桶表
SORTED BY 按照字段排序(一般不用、使用只能創建一個分區)
ROW FORMAT 指定每一行中字段的分隔符:row format delimited fields terminated by '\t'
STORED AS 指定存儲文件類型
常用存儲文件類型:SEQUENCEFILE(二進制序列文件)、TEXTFILE(文本)、ORCFILE(列式存儲文件)
如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用STORED AS SEQUENCEFILE
LOCATION 指定表在HDFS上的存儲位置
①創建內部表
#使用標准的建表語句直接建表 use myhive; create table stu(id int, string name); #可以通過insert into向hive表中插入數據,但是不建議在工作當中這么做;因為每個insert語句會轉換mr后生成一個文件,產生大量小文件 insert into stu(id,name) values(1,"zhangshan"); insert into stu(id,name) values(2,"lisi"); select * from stu; #查詢建表法,通過as查詢語句完成建表,將查詢結果存入新表里 create table if not exists myhive.stu1 as select id, name from stu; select * from stu1;#表中有數據 #like建表法,根據已存在的表結構創建表 create table if not exists myhive.stu2 like stu; select * from stu2;#表中沒有數據
#查詢表類型 desc formatted myhive.stu;
②創建外部表
外部表因為是指定其他的hdfs路徑的數據加載到表當中來,所以hive表會認為自己不完全獨占這份數據,所以刪除hive表時,數據仍存放在hdfs當中,不會刪掉
create external table myhive.teacher(t_id string, t_name string) row format delimited fields terminated by '\t';
創建外部表的時候需要加上external關鍵字
LOCATION字段可以指定,也可以不指定,指定就是數據存放的具體目錄,不指定使用默認目錄:/usr/hive/warehouse
向外部表當中加載數據:
外部表也可以通過insert的方式進行插入數據,一般不推薦,實際工作中都是使用load的方式加載數據到內部表或外部表
load數據可以沖本地文件系統加載或者也可以沖hdfs上面的數據進行加載
從本地文件系統加載數據到teacher表當中去:
load data local inpath '/home/hadoop/teacher.csv' into table myhive.teacher;
從hdfs上加載文件到teacher(將teacher.csv上傳到 hdfs中,在從hdfs上加載)
load data inpath '/hdfsdatas/teachers.csv' into table myhive.teacher;
③內部表與外部表的轉換
#內部表轉換為外部表 alter table stu set tblproperties('EXTERNAL'='TRUE'); #外部表轉換為內部表 alter table teacher set tblproperties('EXTERNAL'='FALSE');
④內部表與外部表的區別
外部表在建表時需要添加external關鍵字
內部表刪除后,表的元數據與真實數據都被刪除,外部表刪除后,僅僅是把該表的元數據刪除,真實數據還在,后期還可以恢復出來
⑤內部表與外部表的使用時機
內部表猶豫刪除表的同時會刪除hdfs的數據文件,所以確定如果一個表僅僅是你獨占使用,其他人不適用的時候可以創建內部表,如果一個表的數據,其他人也要使用,那么就創建外部表。
一般外部表都是用在數據倉庫的ODS層,內部表都是用在數據倉庫的DW層。
⑥hive的分區表
如果hive當中所有的數據都存入到一個文件夾下面,那么在使用MR計算程序的時候,讀取一整個目錄下面的所有文件來進行計算就會變得特別慢,因為數據量太大了。
實際工作中一般都是計算前一天的數據,所以我們只需要將前一天的數據挑出來放到一個文件夾下面即可,專門去計算一天的數據。
這樣就可以使用hive當中的分區表,通過分文件夾的形式,將每一天的數據都分成為一個文件夾,然后我們計算數據的時候通過指定前一天的文件夾即可只計算前一天的數據。
在大數據中,最常用的一種思想就是分治,我么可以把大的文件切割成一個個小的文件,這樣每次操作一個小的文件就很容易了,同樣的道理,在hive中也支持這種思想,就是我們可以把大量的數據按照每天,或者每個小時進行切分成一個個的小文件,這樣去操作小文件就會容易的多了。
在文件系統上建立文件夾,把表的數據放在不同文件夾下面,加快查詢速度。
創建分區表語法
create table score(s_id string, c_id string, s_score int) partitioned by (month string) row format delimited fields terminated by '\t';
創建一個表帶有多個分區
create table score2(s_id string, c_id string, s_score int) partitioned by (year string, month string, day string) row format delimited fields terminated by '\t';
加載數據到分區表當中
load data local inpath '/home/hadoop/score.csv' into table score partition (month='202011');
加載數據到多分區表中
load data local inpath '/home/hadoop/socre.csv' into table score2 partition(year='2020', month='11', day='11');
查看分區
show partitions score;
添加一個分區
alter table score add partition(month='202010');
添加多個分區:添加分區后hdfs文件系統當中看到表下面多了一個文件夾
alter table score add partition(month='202009') partition(month='202008');
刪除分區
alter table score drop partition(month='202009');
表的修復:建立表與數據文件之間的關系映射
msck repair table score4;
⑦hive的分桶表
分桶是相對分區進行更細顆粒度的划分
hive表或分區表可進一步分桶
分桶將整個數據內容按照某列取hash值,對桶的個數取模的方式決定該條記錄存放到哪個桶當中;具有相同hash值的數據進入到同一個文件中
作用:取樣sampling更高效,沒有分桶的話需要掃描整個數據集,提升某些查詢操作效率,例如map、side、join
創use myhive;
#創建分桶表前需要開啟分桶表的支持 set hive.enforce.bucketing=true; #設置與桶相同的reduce個數(默認只有一個reduce) set mapreduce.job.reduces=4; #創建分桶表 create table myhive.user_buckets_demo(id int, name string) clustered by(id) into 4 buckets row format delimited fields terminated by '\t';
#無法直接將數據加載到分桶表中,需要先將數據加載到普通表,普通表到分桶表導入數據會根據id進行hash分桶
#創建普通表 create table user_demo(id int, name string) row format delimited fields terminated by '\t';
數據文件buckets.txt
1 test1 2 test2 3 test3 4 test4 5 test5 6 test6 7 test7 8 test8 9 test9
加載數據到普通表user_demo中
load data local inpath '/home/hadoop/buckets.txt' overwrite into table user_demo;
加載數據到分桶表user_buckets_demo
insert into table user_buckets_demo select * from user_demo;
抽樣查詢桶表的數據
tablesample(bucket x out of y),x表示從第幾個桶開始抽取數據,y與進行采樣的桶數的個數、每個采樣桶的采樣比例有關。
select * from user_buckets_demo tablesample(bucket 1 out of 2); #需要采樣的總桶數=4/2=2個 #先從第一個桶中取出數據 #1+2=3再從第3個桶中取出數據
6.Hive數據導入
#直接向表中插入數據(不推薦使用) insert into table score3 partition(month='201807')values('001', '002', '100'); #通過load加載數據 load data [local] inpath 'datapath' [overwrite] into table stu [partcol1=val1,...]; #通過查詢加載數據 insert overwrite table score3 partition(month='201806') select s_id,c_id,s_score from score; #查詢語句創建表並加載數據 create table score3 as select * from score; #創建表示指定location,將文件上傳到hdfs的指定目錄 create table score3(s_id string, c_id string, s_score int) row format delimited fields terminated by '\t' location '/myscore3'; #export與import(內部表操作) export table teacher to '/home/hadoop/teacher';導出數據 import table teacher from '/home/hadop/teacher';導入數據
7.Hive數據導出
1)insert導出
#將查詢結果導出到本地 insert overwrite local directory '/home/hadoop/stu' select * from stu; #將查詢結果格式化導出到本地 insert overwrite local directory 'home/hadoop/stu' row format delimited fields terminated by ',' select * from stu; #將查詢結果導出到hdfs上 insert overwrite directory 'hdfsdatas/stu' row format delimited fields terminated by ',' select * from stu;
2)hive shell 命令導出
hive -e "hql語句" > file
hive -f hql腳本 > file
3)export導出到hdfs上
export table stu to '/hdfsdatas/stu'
8.Hive的靜態分區與動態分區
靜態分區:表的分許字段值需要開發人員手動給定
創建表導入數據查看ddl中的分區表
動態分區:按照需求實現吧數據自動導入到表的不同分區中,不需要手動指定
#創建普通表 create table t_order(order_numer string, order_price double, order_time string) row format delimited fields terminated by '\t'; #創建目標分區表 create table t_dynamic_partition(order_number string, order_price double) partitioned by(order_time string) row format delimited fields terminated by '\t'; #數據文件 order_partition.txt 10001 100 2019-03-02 10002 200 2019-03-02 10003 300 2019-03-03 10004 400 2019-03-03 10005 500 2019-03-04 10006 600 2019-03-04 #像普通表中加載數據 load data local inpath '/home/hadoop/order_partition.txt' into table t_order; #動態加載數據到分區表中 #開啟動態分區功能 set hive.exec.dynamic.partition=true;
#設置hive為非嚴格模式 set hive.exec.dynamic.partition.mode=nonstrict; insert into table order_dynamic_partition partition(order_time) select order_number, order_price, order_time from t_order;