0.補(bǔ)充
0.1 什么是hive
1. Hive:由Facebook開源用于解決'海量結(jié)構(gòu)化日志'的數(shù)據(jù)統(tǒng)計(jì)'工具'。
2. Hive是基于Hadoop的一個(gè)'數(shù)據(jù)倉庫工具',可以將結(jié)構(gòu)化的數(shù)據(jù)文件'映射'為一張表,并提供類SQL查詢功能。
3. '本質(zhì)':將HQL轉(zhuǎn)化成MapReduce程序
4. '原理介紹'
(1)Hive處理的數(shù)據(jù)存儲(chǔ)在HDFS
(2)Hive分析數(shù)據(jù)底層的實(shí)現(xiàn)是MapReduce
(3)執(zhí)行程序運(yùn)行在Yarn上
0.2 優(yōu)缺點(diǎn)
-- 1. 優(yōu)點(diǎn):
1. 操作接口采用類SQL語法,提供快速開發(fā)的能力(簡(jiǎn)單、容易上手)。
2. 避免了去寫MapReduce,減少開發(fā)人員的學(xué)習(xí)成本。
3. Hive的執(zhí)行延遲比較高,因此Hive常用于數(shù)據(jù)分析,對(duì)實(shí)時(shí)性要求不高的場(chǎng)合。
4. Hive優(yōu)勢(shì)在于處理大數(shù)據(jù),對(duì)于處理小數(shù)據(jù)沒有優(yōu)勢(shì),因?yàn)镠ive的執(zhí)行延遲比較高。
5. Hive支持用戶自定義函數(shù),用戶可以根據(jù)自己的需求來實(shí)現(xiàn)自己的函數(shù)。
-- 2. 缺點(diǎn)
1. Hive的HQL表達(dá)能力有限
2. 迭代式算法無法表達(dá)
3. 數(shù)據(jù)挖掘方面不擅長(zhǎng),由于MapReduce數(shù)據(jù)處理流程的限制,效率更高的算法卻無法實(shí)現(xiàn)。
4. Hive的效率比較低
(1)Hive自動(dòng)生成的MapReduce作業(yè),通常情況下不夠智能化
(2)Hive調(diào)優(yōu)比較困難,粒度較粗
0.3 Hive架構(gòu)原理

-- 1. 用戶接口:Client
CLI(command-line interface)、JDBC/ODBC(jdbc訪問hive)、WEBUI(瀏覽器訪問hive)
-- 2. 元數(shù)據(jù):Metastore
元數(shù)據(jù)包括:
a、表名
b、表所屬的數(shù)據(jù)庫(默認(rèn)是default)
c、表的擁有者
d、列/分區(qū)字段
e、表的類型(是否是外部表)、
f、表的數(shù)據(jù)所在目錄等;
'默認(rèn)存儲(chǔ)在自帶的derby數(shù)據(jù)庫中,推薦使用MySQL存儲(chǔ)Metastore'
-- 3. Hadoop
使用HDFS進(jìn)行存儲(chǔ),使用MapReduce進(jìn)行計(jì)算。
-- 4. 驅(qū)動(dòng)器:Driver
1. '解析器'(SQL Parser):將SQL字符串轉(zhuǎn)換成抽象語法樹AST,這一步一般都用第三方工具庫完成,
比如antlr;對(duì)AST進(jìn)行語法分析,比如表是否存在、字段是否存在、SQL語義是否有誤。
2. '編譯器'(Physical Plan):將AST編譯生成邏輯執(zhí)行計(jì)劃。
3. '優(yōu)化器'(Query Optimizer):對(duì)邏輯執(zhí)行計(jì)劃進(jìn)行優(yōu)化。
4. '執(zhí)行器'(Execution):把邏輯執(zhí)行計(jì)劃轉(zhuǎn)換成可以運(yùn)行的物理計(jì)劃。對(duì)于Hive來說,就是MR/Spark。
0.4 hive與數(shù)據(jù)庫的比較
由于 Hive 采用了類似SQL 的查詢語言 HQL(Hive Query Language),因此很容易將 Hive 理解為數(shù)據(jù)庫。其實(shí)從結(jié)構(gòu)上來看,Hive 和數(shù)據(jù)庫除了擁有類似的查詢語言,再無類似之處
-- 1. 查詢語言
hive有類似sql的hql查詢語言
-- 2. 數(shù)據(jù)更新
1. hive針對(duì)數(shù)據(jù)倉庫而設(shè)計(jì),適合讀多寫少的場(chǎng)景
2. mysql的數(shù)據(jù)需要經(jīng)常進(jìn)行修改。
-- 3. 執(zhí)行延遲
1. hive沒有索引 + 基于mr計(jì)算,延遲性高;
2. 這個(gè)低是有條件的,即數(shù)據(jù)規(guī)模較小,當(dāng)數(shù)據(jù)規(guī)模大到超過數(shù)據(jù)庫的處理能力的時(shí)候,Hive的并行計(jì)算顯然能體現(xiàn)出優(yōu)勢(shì)
-- 4. 數(shù)據(jù)規(guī)模
1. 支持大數(shù)據(jù)規(guī)模的數(shù)據(jù)
0.5 tez引擎
1. 'mr引擎':每個(gè)任務(wù)及任務(wù)之間都需要落盤
2. 'Tez引擎':可以將多個(gè)有依賴的作業(yè)轉(zhuǎn)換為一個(gè)作業(yè),這樣只需寫一次HDFS,且中間節(jié)點(diǎn)較少,從而大大提升作業(yè)的計(jì)算性能。

一、HiveJDBC客戶端基本操作
1.1 HvieJDBC的登入與退出
-- 方式一:使用beeline方式
訪問方式:beeline -u jdbc:hive2://hadoop102:10000 -n lianzp
退出方式:!quit 、!exit 、 ctrl + c
前提:mysql服務(wù)和hiveservice2服務(wù)一定要啟動(dòng)
-- 方式二: 使用hive的方式
訪問方式:hive
退出方式:quit; exit;
1.2 Hive常用的交互命令
“-e” 不進(jìn)入hive的交互窗口執(zhí)行sql語句**
“-f” 執(zhí)行腳本中sql語句**
1.3 Hive數(shù)據(jù)類型
- 基本數(shù)據(jù)類型
| Hive數(shù)據(jù)類型 | Java數(shù)據(jù)類型 | 長(zhǎng)度 | 例子 |
|---|---|---|---|
| TINYINT | byte | 1byte有符號(hào)整數(shù) | 20 |
| SMALINT | short | 2byte有符號(hào)整數(shù) | 20 |
| INT | int | 4byte有符號(hào)整數(shù) | 20 |
| BIGINT | long | 8byte有符號(hào)整數(shù) | 20 |
| BOOLEAN | boolean | 布爾類型,true或者false | TRUE FALSE |
| FLOAT | float | 單精度浮點(diǎn)數(shù) | 3.14159 |
| DOUBLE | double | 雙精度浮點(diǎn)數(shù) | 3.14159 |
| STRING | string | 字符系列??梢灾付ㄗ址???梢允褂脝我?hào)或者雙引號(hào)。 | ‘now is the time’ “for all good men” |
| TIMESTAMP | 時(shí)間類型 | ||
| BINARY | 字節(jié)數(shù)組 |
重點(diǎn)關(guān)注:int,string,double,bigint ;
使用注意事項(xiàng):在sql中需要指定字段的長(zhǎng)度,而在hive中不需要,可以理解為可變參數(shù) ;
數(shù)據(jù)類型的字節(jié)數(shù):
byte short int long float double char 1 2 4 8 4 8 2 其中float的取值范圍比long還要大。
-
集合數(shù)據(jù)類型
數(shù)據(jù)類型 描述 語法示例 STRUCT 和c語言中的struct類似,都可以通過“點(diǎn)”符號(hào)訪問元素內(nèi)容。例如,如果某個(gè)列的數(shù)據(jù)類型是STRUCT{first STRING, last STRING},那么第1個(gè)元素可以通過字段.first來引用。 struct()例如struct<street:string, city:string> MAP MAP是一組鍵-值對(duì)元組集合,使用數(shù)組表示法可以訪問數(shù)據(jù)。例如,如果某個(gè)列的數(shù)據(jù)類型是MAP,其中鍵值對(duì)是’first’->’John’和’last’->’Doe’,那么可以通過字段名[‘last’]獲取最后一個(gè)元素 map()例如map<string, int> ARRAY 數(shù)組是一組具有相同類型和名稱的變量的集合。這些變量稱為數(shù)組的元素,每個(gè)數(shù)組元素都有一個(gè)編號(hào),編號(hào)從零開始。例如,數(shù)組值為[‘John’, ‘Doe’],那么第2個(gè)元素可以通過數(shù)組名[1]進(jìn)行引用。 Array()例如array<string>
創(chuàng)建表的實(shí)例:
create table if not exists test(
name string,
friends array<string>, /*--數(shù)組的格式--*/
children map<string, int>, /*--集合的格式--*/
address struct<street:string, city:string>/* --Struct格式-- */
)
row format delimited fields terminated by ','
/* 行 格式 劃分屬性 以‘,’分割 ,統(tǒng)稱為列分割符*/
collection items terminated by '_'
/*集合(數(shù)組,集合,Struct) 多個(gè)元素之間以‘_’ 分割,則要求所有的數(shù)據(jù)的格式均是一樣的*/
map keys terminated by ':'
/*指明集合中key和value以‘:’ 進(jìn)行分割*/
lines terminated by '\n';
/*行數(shù)據(jù),以換行符進(jìn)行分割*/
獲取集合中屬性的方式:
* 數(shù)組:使用索引的方式:字段名[index]
*
* 集合:使用key的值獲取:字段名[key的值]
*
* Struct:使用:字段.屬性值
1.4 類型轉(zhuǎn)化
- 隱式類型轉(zhuǎn)換規(guī)則
任何整數(shù)類型都可以隱式地轉(zhuǎn)換為一個(gè)范圍更廣的類型,如TINYINT可以轉(zhuǎn)換成INT,INT可以轉(zhuǎn)換成BIGINT;
所有整數(shù)類型、FLOAT和STRING類型都可以隱式地轉(zhuǎn)換成DOUBLE;
TINYINT、SMALLINT、INT都可以轉(zhuǎn)換為FLOAT;
BOOLEAN類型不可以轉(zhuǎn)換為任何其它的類型。
-
CAST操作顯示進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
-- 示例: select cast ('1' as int) + 3 ; /* 4 */ select '1' + 3 ; /* 4.0 */
二、DDL數(shù)據(jù)定義
2.1 數(shù)據(jù)庫操作
2.1.1顯示和查詢數(shù)據(jù)庫與表信息
1.顯示數(shù)據(jù)庫
show databases;
2.切換數(shù)據(jù)庫
use 數(shù)據(jù)庫名;
3.查詢數(shù)據(jù)庫詳細(xì)信息
desc database [extended] 數(shù)據(jù)庫名
4.查詢表的詳細(xì)信息
desc [formatted] 表名
2.1.2 創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path]
[WITH DBPROPERTIES (property_name=property_value, ...)];
實(shí)例:
1.create database db_hive;
2.create database if not exists db_hive;
/* 加上 if not exists 后,當(dāng)該數(shù)據(jù)庫已存在時(shí),不拋異常,也不做創(chuàng)建數(shù)據(jù)庫的操作*/
3.create database db_hive2 location '/db_hive2.db';
/*指定數(shù)據(jù)創(chuàng)建時(shí),在hdfs上的路徑,如果沒有此操作,則默認(rèn)的路徑為:/user/hive/warehouse/數(shù)據(jù)庫名*/
2.1.3 刪除數(shù)據(jù)庫
1.刪除空的數(shù)據(jù)庫(何為空的數(shù)據(jù)庫?指該數(shù)據(jù)中沒有表)
drop database db_hive2 ;
2.當(dāng)數(shù)據(jù)庫不存在時(shí),避免拋異常
drop database if not exists db_hive2 ;
3.當(dāng)數(shù)據(jù)庫不為空時(shí),加上cascade進(jìn)行刪除
drop database if not exists db_hive2 cascade ;
2.2 表的操作
2.2.1 建表語法
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], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
各個(gè)參數(shù)說明:
EXTERNAL :表示外部表,在刪除表時(shí),只會(huì)刪除mysql中的元數(shù)據(jù),在hdfs的真實(shí)數(shù)據(jù)不會(huì)被刪除,如果沒EXTERNAL ,則刪除表的時(shí)候,元數(shù)據(jù)和真實(shí)數(shù)據(jù)均為被刪除。
IF NOT EXISTS :當(dāng)表存在時(shí),添加此操作,則不會(huì)拋異常,同時(shí)也不會(huì)執(zhí)行建表操作。
COMMENT :字段或表的注釋;
PARTITIONED BY : 分區(qū)
(后面詳細(xì)講);CLUSTERED BY : 分桶(后面詳細(xì)講);
-
SORTED BY :文件在hdfs的存儲(chǔ)格式 ,存儲(chǔ)的方式有:SEQUENCEFILE(二進(jìn)制序列文件)、TEXTFILE(文本)、RCFILE(列式存儲(chǔ)格式文件)
如果文件數(shù)據(jù)是純文本,可以使用STORED AS TEXTFILE。如果數(shù)據(jù)需要壓縮,使用 STORED AS SEQUENCEFILE;
ROW FORMAT row_format :列分割符;
LOCATION hdfs_path:指定表在HDFS上的存儲(chǔ)位置;默認(rèn)為當(dāng)前庫下。
AS select_statement :建表時(shí)進(jìn)行加載數(shù)據(jù),通過as后面的查詢語句。
2.2.2 管理表與外部表
區(qū)別:
1.管理表:也稱內(nèi)部表,當(dāng)刪除管理表時(shí),hdfs中的數(shù)據(jù)和mysql中的元數(shù)據(jù)均會(huì)被刪除 -- 控制表的生命周期
2.外部表:當(dāng)刪除管理表時(shí),hdfs中的數(shù)據(jù)不會(huì)被刪除,mysql中的元數(shù)據(jù)會(huì)被刪除 -- 不能控制表的生命周期
在實(shí)戰(zhàn)過程中,我們一般都是使用外部表。
內(nèi)外部表的定義、查看和轉(zhuǎn)換
1.定義:
創(chuàng)建表單時(shí),加上 external 關(guān)鍵字則表示為外部表。
2.查看:
通過 desc formatted 表名 。
3.轉(zhuǎn)換:
alter table 表名 set tblproperties('EXTERNAL'='TRUE');
注意事項(xiàng):
a、TRUE : 轉(zhuǎn)換為外部表;
b、FALSE : 轉(zhuǎn)換為內(nèi)部表;
c、('EXTERNAL'='TRUE')和('EXTERNAL'='FALSE')為固定寫法,均需要大寫!
2.2.3 修改表
- 重命名表
-- 語法:
alter table 舊表名 rename to 新表名 ;
-- 示例:
alter table dept_partition2 rename to dept_partition3;
- 更新列
-- 語法:
alter table 表名 change 舊列名 新列名 數(shù)據(jù)類型
-- 示例:
alter table emp change ename naem string first deptno;
- 增加列
-- 語法:
alter table 表名 add 列名 數(shù)據(jù)類型 [字段注釋] [first / after 列名]
-- 示例:
alter table emp add loc string ;
- 刪除表
-- 語法:
drop table 表名
-- 示例:
drop table emp ;
三、DML 操作
注意事項(xiàng):
當(dāng)導(dǎo)入數(shù)據(jù)時(shí),如果加載本地的文件,并是將數(shù)據(jù)加載到有分區(qū)和分桶表的hive表中時(shí),因?yàn)榇藢?dǎo)入數(shù)據(jù)的過程會(huì)跑mr程序,該本地文件需要在所有節(jié)點(diǎn)都需要,不然會(huì)報(bào)文件不存在異常。
3.1 數(shù)據(jù)的導(dǎo)入
3.1.1 方式一
- 使用load
-- 語法:
load data [local] inpath '數(shù)據(jù)的路徑' [overwrite] into table 表名 [partition (分區(qū)字段 = value1) (分區(qū)字段 = value2)]
-- 說明:
local : 如果使用了,則'數(shù)據(jù)的路徑'寫linux本地的路徑;
如果未使用,則'數(shù)據(jù)的路徑'寫hdfs上的路徑;
partition (分區(qū)字段 = value1) :表示數(shù)據(jù)上傳到哪一個(gè)分區(qū),后面詳細(xì)介紹。
overwrite : 表示覆蓋寫。
-- 示例:
本地 : load data local inpath '/opt/module/hive/datas/emp' into table emp;
hdfs : load data inpath '/user/hive/warehouse/emp' into table emp;
3.1.2 方式二
- 通過查詢語句向表中進(jìn)行添加
-- 語法:
1) insert into table 表名 select 字段 from 表名; -- 追加的方式,原數(shù)據(jù)不會(huì)丟失
2) insert overwrite table 表名 select 字段 from 表名; -- 覆蓋原數(shù)據(jù)的方式,原數(shù)據(jù)被覆蓋
3) insert into table 表名 select 字段 from 表名 partition (分區(qū)字段 = Value); 多分區(qū)的插入模式
-- 示例:
1) insert into table emp select id ,name from emp1;
2) insert overwrite table emp select id ,name from emp1;
3) insert into table emp select id ,name from emp1 partition (month = '2020-02-04');
3.1.3 方式三
- 創(chuàng)建表并使用查詢語句加載數(shù)據(jù)(As Select)
-- 語法:
建表語句 + as + 查詢語句
-- 示例:
create [external] table [if not exists] emp (
id int ,
name string
)
row format delimited fields terminated by '\t'
as select id , name from emp1;
3.1.4 方式四
- 創(chuàng)建表時(shí)使用location的方式
-- 語法:
建表語句 + location + 'hdfs數(shù)據(jù)路徑'
-- 說明:
數(shù)據(jù)路徑:只能是hdfs上的路徑,當(dāng)該路徑是一個(gè)目錄時(shí),則表示加載該文件夾下的所有文件
-- 示例:
create [external] table [if not exists] emp (
id int ,
name string
)
row format delimited fields terminated by '\t'
location '/user/hive/warehouse/emp' ;
3.1.5 方式五
- 使用import方式
注意:必須使用export的方式導(dǎo)出以后(導(dǎo)出了元數(shù)據(jù)和真實(shí)數(shù)據(jù)),再使用import進(jìn)行導(dǎo)入。
-- 示例:
import table student2 from '/user/hive/warehouse/export/student'
3.2 數(shù)據(jù)的導(dǎo)出
- 說明:數(shù)據(jù)的導(dǎo)出的方式,使用的情況很少。
3.2.1 方式一
- insert 方式
-- 語法:
insert overwrite [local] directory '輸出文件路徑' [row format delimited fields terminated by '分割符'] 查詢語句
-- 說明:
overwrite :overwrite 是覆蓋原文件的數(shù)據(jù)寫入
[local] :加它,表示導(dǎo)出到本地,不加,則表示導(dǎo)出到hdfs上
'輸出文件路徑' : 配合local來的,加了local,則寫本地linux路徑,不加,則寫hdfs路徑
[row format delimited fields terminated by '分割符'] :表示文件輸出的格式
-- 示例:
-- 導(dǎo)入到本地
1)insert overwrite local directory '/opt/module/hive/datas/export/student' select * from student;
-- 導(dǎo)出到本地,并指定導(dǎo)出的行數(shù)據(jù)的分割符
2)insert overwrite local directory '/opt/module/hive/datas/export/student1' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
-- 導(dǎo)出到hdfs上,并指定導(dǎo)出的行數(shù)據(jù)的分割符
3)insert overwrite directory '/user/lianzp/student2'ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
3.2.2 方式二
- hadoop 的shell命令
-- 語法:
hdfs dfs -get hdfs數(shù)據(jù)的輸出路徑 linux輸入路徑
3.2.3 方式三
- hive 的shell命令
-- 語法:
hive -e 查詢語句 > linux輸入路徑
3.2.4 方式四
- export的方式
說明:export 和 import 主要用于兩個(gè)hadoop 平臺(tái)集群之間的hive表遷移。
-- 語法:
export table 表名 to '文件輸出路徑' -- 此路徑為hdfs路徑
3.2.5 方式五
- Sqoop 導(dǎo)出 -- > 后續(xù)有課程單獨(dú)講解
3.3 清除表中數(shù)據(jù)
- 使用 truncate
-- 語法:
truncate table 表名 ;
四、查詢
4.1 關(guān)鍵詞的總結(jié)
-- 建表:
1) partitioned by :分區(qū)表
2)clustered by : 分桶表
-- 查詢:
1) order by : 全排序
2) distribute by : 查詢中做分區(qū)
3) sort by : 查詢中每個(gè)MapReduce內(nèi)部排序
4) cluster by : 查詢中做分區(qū)排序
-- 窗口函數(shù):
1) partition by :窗口函數(shù)中做分區(qū)
2) order by :窗口函數(shù)中做排序
4.2 sql執(zhí)行的順序
1. from ;
2. on ;
3. join ;
4. where ; -- 不能使用列的別名
5. group by ; -- 不能使用列的別名
6. having ; -- 可以使用列的別名
7. select ;
8. distinct ;
9. order by ; -- 可以使用列的別名
10. limit ; -- 可以使用列的別名
注意事項(xiàng): 表名一旦使用了別名,所有的位置均需使用表的別名。
4.3 查詢語法
-- 語法:
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUST BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]
-- 說明:
DISTINCT :去重;
CLUST BY col_list
4.4 基本查詢
4.4.1 全表和特定列查詢
-- 語法:
select * from 表名 ; -- 全表查詢
select 列名1、列名2 from 表名 ; -- 特定列查詢
4.4.2 別名
定義: 在查詢中緊跟列名,也可以在列名與別名之間加as;
注意事項(xiàng):
1)在hive中,中文的別名使用 一對(duì) `` 來注釋;
2)as 一般可以省略 ;
3) where 、 group by 后面不能使用列的別名;
4)having 、order by 、limit 可以使用列的別名 ;
4.4.3 算術(shù)運(yùn)算符
| 運(yùn)算符 | 描述 |
|---|---|
| A+B | A和B 相加 |
| A-B | A減去B |
| A*B | A和B 相乘 |
| A/B | A除以B |
| A%B | A對(duì)B取余 |
| A&B | A和B按位取與 |
| A|B | A和B按位取或 |
| A^B | A和B按位取異或 |
| ~A | A按位取反 |
4.4.4 常用函數(shù)
1) c求和 : sum();
2) 求平均數(shù) : avg () ;
3) 求最大值 : max();
4) 求最小值 : min();
5) 求個(gè)數(shù) : count();
-- 說明:
1) count():不計(jì)算null值;
2) avg () : 計(jì)算平均數(shù)時(shí),分母也是不計(jì)算null個(gè)數(shù)的;
3) 所以: avg (字段) = sum (字段) / count(字段),因此我們?cè)谟?jì)算一些列的平均值時(shí),一般使用count(*)或者是count(1);
4.4.5 Where 語句
1) 條件的篩選;
2) 緊跟from后面。
4.4.6 比較運(yùn)算符
| 操作符 | 支持的數(shù)據(jù)類型 | 描述 |
|---|---|---|
| A=B | 基本數(shù)據(jù)類型 | 如果A等于B則返回TRUE,反之返回FALSE |
| A<=>B | 基本數(shù)據(jù)類型 | 如果A和B都為NULL,則返回TRUE,如果一邊為NULL,返回False |
| A<>B, A!=B | 基本數(shù)據(jù)類型 | A或者B為NULL則返回NULL;如果A不等于B,則返回TRUE,反之返回FALSE |
| A<B | 基本數(shù)據(jù)類型 | A或者B為NULL,則返回NULL;如果A小于B,則返回TRUE,反之返回FALSE |
| A<=B | 基本數(shù)據(jù)類型 | A或者B為NULL,則返回NULL;如果A小于等于B,則返回TRUE,反之返回FALSE |
| A>B | 基本數(shù)據(jù)類型 | A或者B為NULL,則返回NULL;如果A大于B,則返回TRUE,反之返回FALSE |
| A>=B | 基本數(shù)據(jù)類型 | A或者B為NULL,則返回NULL;如果A大于等于B,則返回TRUE,反之返回FALSE |
| A [NOT] BETWEEN B AND C | 基本數(shù)據(jù)類型 | 如果A,B或者C任一為NULL,則結(jié)果為NULL。如果A的值大于等于B而且小于或等于C,則結(jié)果為TRUE,反之為FALSE。如果使用NOT關(guān)鍵字則可達(dá)到相反的效果。 |
| A IS NULL | 所有數(shù)據(jù)類型 | 如果A等于NULL,則返回TRUE,反之返回FALSE |
| A IS NOT NULL | 所有數(shù)據(jù)類型 | 如果A不等于NULL,則返回TRUE,反之返回FALSE |
| IN(數(shù)值1, 數(shù)值2) | 所有數(shù)據(jù)類型 | 使用 IN運(yùn)算顯示列表中的值 |
| A [NOT] LIKE B | STRING 類型 | B是一個(gè)SQL下的簡(jiǎn)單正則表達(dá)式,也叫通配符模式,如果A與其匹配的話,則返回TRUE;反之返回FALSE。B的表達(dá)式說明如下:‘x%’表示A必須以字母‘x’開頭,‘%x’表示A必須以字母’x’結(jié)尾,而‘%x%’表示A包含有字母’x’,可以位于開頭,結(jié)尾或者字符串中間。如果使用NOT關(guān)鍵字則可達(dá)到相反的效果。 |
| A RLIKE B, A REGEXP B | STRING 類型 | B是基于java的正則表達(dá)式,如果A與其匹配,則返回TRUE;反之返回FALSE。匹配使用的是JDK中的正則表達(dá)式接口實(shí)現(xiàn)的,因?yàn)檎齽t也依據(jù)其中的規(guī)則。例如,正則表達(dá)式必須和整個(gè)字符串A相匹配,而不是只需與其字符串匹配。 |
4.4.7 like 和 rlike
1) like
% : 代表零個(gè)或者是多個(gè)字符(即時(shí)任意字符)
_ : 代表一個(gè)字符;
\ : 轉(zhuǎn)義字符;
2) Rlike :后面緊跟隨正則表達(dá)式
\ : 轉(zhuǎn)義字符,即屏蔽特殊字符的含義:\$;
^ : 從頭開始匹配,如:name rlike ^a : 表示以a開頭的name
$ : 匹配結(jié)尾 ,如 name Rlike t$ :匹配以t結(jié)尾的name
* : 0-n 個(gè) ,如 name rlike a* : 匹配 0-n a的name
[] : 表示范圍,如 [0-9,a-z]:匹配0-9或者是a-z都可以。
4.4.8 邏輯運(yùn)算符
| 操作符 | 含義 |
|---|---|
| AND | 邏輯并 |
| OR | 邏輯或 |
| NOT | 邏輯否 |
4.5 分組
4.5.1 group by
- 常和聚合函數(shù)在一起;
- 出現(xiàn)在 group by 中的字段可以出現(xiàn)在 select中,也可以不出現(xiàn),
但是出現(xiàn)在 select中字段(除函數(shù)和常量外)必須在group by 出現(xiàn)過的字段。
4.5.1 Having
having 與 where 的不同
1) where 后面不能寫分組函數(shù),但是 having 可以 ;
2) having 只用于 Group by 分組統(tǒng)計(jì)語句;
4.6 join
-- 說明:
1) 常見的7種 join 要會(huì)寫;
2) 不支持非等值連接;
3) 支持滿外連接 : full join ;
4) 關(guān)于主表和從表: -- 左右外連接,主表數(shù)據(jù)全要,從表數(shù)據(jù)只要交集的部分。
左外連接 : 左邊為主表,右邊為從表 ;
右外連接 : 右邊為主表,左邊為從表。
4.7 排序
4.7.1 全局排序 : Order By
1) 全局排序,只能有一個(gè)Reducer ;
2) DESC : 降序 ;
3) ASC : 升序('默認(rèn)值');
4) Order by 子句必須在SELECT語句的結(jié)尾 ;
5) 排序的字段可以是多個(gè);
示例:
select id , name ,sal from emp order by sal desc ,name asc ;
-- 先按照薪水降序,薪水相同的,則按照名字進(jìn)行升序排序;
4.7.2 mapreduce內(nèi)部排序 :sort by
1) 理解:
理解為在 reduce 中進(jìn)行排序。所以一般是需要有多個(gè) reduce 才有作用,是在每個(gè)reduce中進(jìn)行排序,屬于局部排序,而不是全局排序。
2) 使用場(chǎng)景:
當(dāng)數(shù)據(jù)量很大時(shí),不要進(jìn)行全局排序,只需要進(jìn)行局部排序。
3) 一般不單獨(dú)使用,因?yàn)闊o法控制什么樣的數(shù)據(jù)進(jìn)入同一個(gè) reduce 中;
-- 一般配合distribute by 使用,分區(qū)排序就是指定什么樣的數(shù)據(jù)會(huì)進(jìn)入同一個(gè)reduce中。
4) 單獨(dú)使用時(shí),進(jìn)入同一個(gè) reduce 任務(wù)中的數(shù)據(jù)是隨機(jī)的。 -- 偽隨機(jī),就是每次計(jì)算的結(jié)果是一樣的,但是進(jìn)入每一個(gè)reduce 中的數(shù)據(jù)是隨機(jī)的。
-- 示例:
1) 設(shè)置reducer的個(gè)數(shù):
set mapreduce.job.reduces=3; -- 設(shè)置reduce個(gè)數(shù)為3
2) 根據(jù)部門編號(hào)降序查看員工信息 :
select * from emp sort by deptno desc;
-- 此時(shí)生成3個(gè)結(jié)果文件,并且每個(gè)結(jié)果文件中均是按照deptno 進(jìn)行降序排序。
4.7.3 分區(qū)排序 : distribute by
1. 理解 : 類似在 MapReduce 中的自定義分區(qū)(partition );
2. 一般就是配合 sort by 使用;
3. 同樣,在使用的時(shí)候,不能是一個(gè)reduce,需要多個(gè)reduce;
4. 什么樣的數(shù)據(jù)會(huì)進(jìn)行同一個(gè)reduce 呢 ?
1)首先,這個(gè)分區(qū)不是很智能,使用的方式是:分區(qū)的字段的 ( hashcode % reduce的個(gè)數(shù) ),計(jì)算值相等的,則進(jìn)入同一個(gè)reduce;
2)不會(huì)使用toString方式進(jìn)行分區(qū)。
5. distribute by 必須寫在sort by 的前面;
6. tez 引擎會(huì)進(jìn)行reduce的優(yōu)化,即假設(shè)設(shè)置為3個(gè)reduce,但是運(yùn)行時(shí)有可能是2個(gè)reduce,所以驗(yàn)證時(shí)032,需使用mr引擎。-- set hive.execution.engine=mr;
-- 示例:
insert overwrite local directory '/opt/module/hive/datas/distribute-result' select * from emp distribute by deptno sort by empno desc; -- 假設(shè) reduce = 3 ;
-- 先按照deptno進(jìn)行分區(qū)(m = hashcode(deptno) % 3 , m值相等的數(shù)據(jù)進(jìn)入同一個(gè)分區(qū)),然后在分區(qū)內(nèi)進(jìn)行局部排序,最后將查詢的結(jié)果導(dǎo)出到本地指定的一個(gè)文件中。
4.7.4 Cluster By
1. 理解 :當(dāng)distribute by 和 sort by 的字段相同時(shí),可以使用Cluster by 進(jìn)行替代;
2. 不能指定排序的順序,只能是升序。
-- 示例:
方式一 :select * from emp cluster by deptno ;
方式二 :select * from emp distribute by deptno sort by deptno ;
-- 方式一和方式二是等價(jià)的。
五、 分區(qū)表和分桶表
5.1 分區(qū)表
分區(qū)表的解析:
-- 理解:
1) Hive 中的分區(qū)就是分目錄 ;
2) 分區(qū)表對(duì)應(yīng)一個(gè)hdfs文件系統(tǒng)的獨(dú)立的文件;
3) 實(shí)際上是把一個(gè)大的數(shù)據(jù)集根據(jù)業(yè)務(wù)的需求分割成多個(gè)小的數(shù)集;
4) 在查詢時(shí),通過where語句進(jìn)行條件篩選,指定數(shù)據(jù)在哪個(gè)分區(qū)內(nèi),提高查詢的效率;
5) 同時(shí)用于解決數(shù)據(jù)傾斜的問題。
5.1.1 分區(qū)表的基本操作
- 創(chuàng)建分區(qū)表
-- 語法:
create table [if not exists] 表名 (
字段1 數(shù)據(jù)類型1,
字段2 數(shù)據(jù)類型2,
字段3 數(shù)據(jù)類型3,
...
)
partition by (字段1 數(shù)據(jù)類型1 , 字段2 數(shù)據(jù)類型2 ,...) -- 分區(qū),字段不能與表中屬性字段相同
clustered by (字段1 , 字段2 , ...) -- 分桶,字段來自于表中的字段,所以是沒有數(shù)據(jù)類型的。
row format delimited fields terminated by '\t'
-- 分區(qū)的字段也是可以作為表的字段使用。
-- 示例:
create table dept_partition(
deptno int ,
dname string ,
loc string
)
partition by (month string , day string) -- 二級(jí)分區(qū),先按照月進(jìn)行分區(qū),在月中再根據(jù)day進(jìn)行分區(qū)
row format delimited fields terminated by '\t'
- 加載數(shù)據(jù)
方式一 : 常規(guī)加載數(shù)據(jù) load方式
-- 語法:
load data local inpath '本地?cái)?shù)據(jù)路徑' into table 表名 partition by (字段1'***',字段2 '***')
-- 示例:
load data local inpath '/opt/module/hive/datas/2020-04-04.log' into table dept_partition partition by (month='2020-04',day='04')
方式二:上傳數(shù)據(jù)后修復(fù) -- 因?yàn)閱为?dú)上傳數(shù)據(jù)到指定的目錄下,hive是不能自動(dòng)讀取,需要進(jìn)行數(shù)據(jù)的修復(fù)
第一步: 根據(jù)分區(qū)字段的信息,創(chuàng)建文件夾,此文件夾與表的路徑相同
第二步: 本地的數(shù)據(jù)上傳到指定的目錄下,使用 【 hdfs dfs -put 本地?cái)?shù)據(jù)路徑 hdfs文件路徑 】
第三步: 進(jìn)行數(shù)據(jù)的修復(fù) ,使用語句 【msck repair table 表名】
方式三: 上傳數(shù)據(jù)后添加分區(qū)的方式 -- 該方式使用的情況最多
第一步和第二步與方式二完全相同;
第三步: 執(zhí)行添加分區(qū)的方式
alter table 表名 add partition (字段1='***',字段2='***')
-- 實(shí)例:
第一步:hdfs dfs -mkdir -p /user/hive/warehouse/dept_partition/month=2020-04/day=04 ;
第二步:hdfs dfs -put /opt/module/hive/datas/2020-04-04.logs /user/hive/warehouse/dept_partition/month=2020-04/day=04
第三步:
方式二: msck repair table dept_partition;
方式二: alter table dept_partition add partition (month='2020-04',day='04');
- 根據(jù)分區(qū)進(jìn)行查詢
-- 語法:
查詢語句 + where 分區(qū)字段='***' ;
-- 示例:
select * from dept_partition where day='04' or day='05' ;
- 增加分區(qū)
-- 語法:
alter table 表名 add partition (字段1="***",字段2='***') partition (字段1="***",字段2='***');
-- 說明:
增加多個(gè)分區(qū)時(shí),分區(qū)與分區(qū)之間使用空格隔開。
- 刪除分區(qū)
-- 語法:
alter table 表名 drop partition (字段1="***",字段2='***') , partition (字段1="***",字段2='***');
-- 說明:
刪除的多個(gè)分區(qū)之間使用','進(jìn)行分隔。
- 查看多個(gè)分區(qū)
-- 語法:
show partitions 表名;
5.1.2 動(dòng)態(tài)分區(qū)調(diào)整
-- 理解:為什么要使用動(dòng)態(tài)分區(qū)呢?
在實(shí)際的情況中,我們的數(shù)據(jù)通過前端收集過來以后,一般都是存儲(chǔ)在hdfs上面,我們只需要通過 insert + 查詢語句的方式將數(shù)據(jù)導(dǎo)入到指定的數(shù)據(jù)表,在此時(shí)需要指定按照什么字段進(jìn)行分區(qū)。
- 前期的準(zhǔn)備工作--開啟動(dòng)態(tài)分區(qū)參數(shù)設(shè)置
(1)開啟動(dòng)態(tài)分區(qū)功能(默認(rèn)true,開啟)
hive.exec.dynamic.partition=true
(2)設(shè)置為非嚴(yán)格模式(動(dòng)態(tài)分區(qū)的模式,默認(rèn)strict,表示必須指定至少一個(gè)分區(qū)為靜態(tài)分區(qū),nonstrict模式表示允許所有的分區(qū)字段都可以使用動(dòng)態(tài)分區(qū)。)
hive.exec.dynamic.partition.mode=nonstrict
(3)在所有執(zhí)行MR的節(jié)點(diǎn)上,最大一共可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)。默認(rèn)1000
hive.exec.max.dynamic.partitions=1000
(4)在每個(gè)執(zhí)行MR的節(jié)點(diǎn)上,最大可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)。該參數(shù)需要根據(jù)實(shí)際的數(shù)據(jù)來設(shè)定。比如:源數(shù)據(jù)中包含了一年的數(shù)據(jù),即day字段有365個(gè)值,那么該參數(shù)就需要設(shè)置成大于365,如果使用默認(rèn)值100,則會(huì)報(bào)錯(cuò)。
hive.exec.max.dynamic.partitions.pernode=100
(5)整個(gè)MR Job中,最大可以創(chuàng)建多少個(gè)HDFS文件。默認(rèn)100000
hive.exec.max.created.files=100000
(6)當(dāng)有空分區(qū)生成時(shí),是否拋出異常。一般不需要設(shè)置。默認(rèn)false
hive.error.on.empty.partition=false
- 實(shí)操
-- 需求:將dept表中的數(shù)據(jù)按照地區(qū)(loc字段),插入到目標(biāo)表dept——partition的分區(qū)中:
1)創(chuàng)建目標(biāo)dept_partition表
create table dept_partition (
id int,
name string
)
partitioned by (loc string)
row format delimited fields terminated by '\t';
2) 插入數(shù)據(jù)
insert into table dept_partition partition (loc) select deptno , name, loc from dept;
5.2 分桶表
-- 理解:為什么會(huì)有分桶表?或者說分桶表是用來解決什么問題呢?
1)提供一個(gè)數(shù)據(jù)隔離和優(yōu)化查詢的便利方式,如當(dāng)某一個(gè)表或者是某一個(gè)分區(qū)的數(shù)據(jù)量特別大時(shí),通過分桶的方式,可以將數(shù)據(jù)再進(jìn)行分解成多個(gè)模塊,這樣在進(jìn)行查詢時(shí),提供了查詢的效率。 -- 說明查詢的分區(qū)操作時(shí)自動(dòng)的。
2)什么樣的數(shù)據(jù)會(huì)進(jìn)入同一個(gè)桶中呢?
通過 (分桶字段的)hashcode % 桶的個(gè)數(shù) ,取模數(shù)相等的進(jìn)入同一個(gè)桶內(nèi)。(不適用于TEZ引擎)
3)分桶表針對(duì)的是數(shù)據(jù)文件;而分區(qū)是針對(duì)數(shù)據(jù)路徑。
創(chuàng)建分桶表
在創(chuàng)建表單時(shí),增加如下語法子句:
******
clustered by (字段1,字段2,***) into num buckets;
******
-- 說明:
1) 字段1-n : 均來自于表中的字段;
2) num : 表示分桶的個(gè)數(shù)。
5.3 抽樣查詢
-- 理解:
當(dāng)數(shù)據(jù)特別大的時(shí)候,我們不要通過查詢所有的數(shù)據(jù)來獲取數(shù)據(jù)的情況。
例如:工廠生產(chǎn)的產(chǎn)品,OQC 是按比例抽樣來判定產(chǎn)品的良率。
-- 示例:
select * from dept tablesample (bucket 1 out of 4 on id);
-- 說明:
on :表示依據(jù)哪個(gè)字段進(jìn)行抽樣;
4 : 表示按照on后面的字段將數(shù)據(jù)分成幾份。
1 : 則表示第一份,2 表示第二份。
如上只是抽樣方法中非常簡(jiǎn)單的一種,還有很多種方式。
六 、函數(shù) (重點(diǎn))
6.1 常用函數(shù)
日期函數(shù):
1) unix_timestamp : 返回當(dāng)前或指定的時(shí)間戳;
SELECT unix_timestamp("2020-05-02 11:22:00"); ==>1588418520
2) from_unixtime : 將時(shí)間戳轉(zhuǎn)化為日期格式
SELECT FROM_unixtime(1588418520); ==> 2020-05-02 11:22:00
3) current_date : 當(dāng)前日期
4)current_timestamp: 當(dāng)前日期 + 時(shí)間;
5)to_date : 獲取日期部分
6)year/month/day/hour/minute/second() : 獲取年、月、日、小時(shí)、分、秒
7)weekofyear(): 當(dāng)前時(shí)間是一年中的第幾周
8)dayofmonth(): 當(dāng)前時(shí)間是一個(gè)月中的第幾天
9)months_between() : 兩個(gè)日期間的月份
10) datediff() : 兩個(gè)日期相差的天數(shù)
11) add_months:日期加減月
12) date_add:日期加天數(shù)
13) date_sub:日期減天數(shù)
14) last_day: 日期的當(dāng)月的最后一天
取整函數(shù)
1) round: 四舍五入
2) ceil: 向上取整
3) floor: 向下取整
字符串函數(shù)
1)upper: 轉(zhuǎn)大寫
2)lower: 轉(zhuǎn)小寫
3)length: 長(zhǎng)度
4)trim: 前后去空格
5)lpad: 向左補(bǔ)齊,到指定長(zhǎng)度
6)rpad: 向右補(bǔ)齊,到指定長(zhǎng)度
7)regexp_replace: SELECT regexp_replace('100-200', '(\\d+)', 'num') ;
使用正則表達(dá)式匹配目標(biāo)字符串,匹配成功后替換!
集合操作
1) size: 集合中元素的個(gè)數(shù)
2) map_keys: 返回map中的key
3) map_values: 返回map中的value
4) array_contains: 判斷array中是否包含某個(gè)元素
5) sort_array: 將array中的元素排序
6.2 系統(tǒng)內(nèi)置函數(shù)
1) 查看系統(tǒng)自帶的函數(shù)
show functions;
2) 查詢函數(shù)的用法
desc function extended 函數(shù)名
6.3 常用的內(nèi)置函數(shù)
6.3.1 空字段賦值 NVL
-- 語法:
nvl(value,default_value)
-- 說明:
1)如果value 為null,則返回default_value ,否則返回vaule;
2)如果兩個(gè)值(value , default_value)均為null,則返回null;
6.3.2 CASE WHEN
-- 示例:
select
dept_id,
sum(case sex when '男' then 1 else 0 end) male_count,
sum(case sex when '女' then 1 else 0 end) female_count
from
emp_sex
group by
dept_id;
/* 解讀:
1.按照dept_id 進(jìn)行分組,同一組的數(shù)據(jù)先進(jìn)行計(jì)算;
2.假設(shè)dept_id=10的數(shù)據(jù)有10條,則10數(shù)據(jù)分別在sum函數(shù)中進(jìn)行計(jì)算,計(jì)算完成以后得出一個(gè)結(jié)果;
3.一組數(shù)據(jù)最后得到一條數(shù)據(jù)結(jié)果。
*/
6.3.3 行轉(zhuǎn)列
-- 相關(guān)函數(shù)
1) concat('str1','str2','str3',...) : 表示將str1/str2/str3... 依次進(jìn)行連接,str1/str2/str3... 可以說任何數(shù)據(jù)類型;
-- 示例:SELECT concat('132','-','456'); ==> 132-456
2) concat_ws('連接符','str1','str2',...) : 表示使用'連接符'將str1/str2...依次進(jìn)行連接,str1/str2...只能是字符串或者是字符串?dāng)?shù)組。
-- 示例:
SELECT concat_ws('-','java','maven'); ==> java-maven;
SELECT concat_ws(null,'java','maven'); ==> null -- 當(dāng)連接符為null時(shí),結(jié)果返回null
SELECT concat_ws('.', 'www', array('facebook', 'com')) ;==> www.facebook.com
3) collect_set(col) : 函數(shù)只接受基本數(shù)據(jù)類型,它的主要作用是將某字段的值進(jìn)行去重匯總,產(chǎn)生array類型字段
-- 示例:
SELECT COLLECT_set(deptno) from emp; ==>[20,30,10]
6.3.4 列轉(zhuǎn)行
-- 語法:
lateral view explode (split(字段,分割符)) 表名 as 列名
-- 說明:
lateral view : 側(cè)寫;
explode(): 將指定的集合拆解分成多行 -- 炸裂
split(字段,分割符) : 將指定的字符串按照分割符封裝成一個(gè)集合。
-- 示例:
SELECT movie,category_name
FROM movie_info
lateral VIEW
explode(split(category,",")) movie_info_tmp AS category_name ; -- categor_name 為炸裂的列名,move_info_tmp為側(cè)寫的表名


6.4 開窗函數(shù)
相關(guān)函數(shù)說明:開窗函數(shù)是為每一條數(shù)據(jù)進(jìn)行開窗
1) over() : 單獨(dú)使用此函數(shù),默認(rèn)的窗口大小為結(jié)果集的大小。
2) partition by : 在窗口函數(shù)中進(jìn)行分區(qū)
over(partition by 字段) :對(duì)結(jié)果集內(nèi)進(jìn)行分區(qū),每條數(shù)據(jù)的開窗大小為該結(jié)果集中分區(qū)集的大小。
3) over( order by 字段) : 在窗口函數(shù)中只用到了order by 排序時(shí),也會(huì)對(duì)每條數(shù)據(jù)進(jìn)行開一個(gè)窗口,默認(rèn)的開窗大小為:從結(jié)果集的開始位置到當(dāng)前處理數(shù)據(jù)的位置。
-- 實(shí)例:
-- 1.查詢?cè)?017年4月份購(gòu)買過的顧客及總?cè)藬?shù)
-- 解析,顧客全部要,多個(gè)顧客,多行,人數(shù)為一個(gè)值,一行,則是需要進(jìn)行開窗,因?yàn)椴皇且灰黄ヅ涞摹? SELECT name ,
COUNT(*) OVER () `人數(shù)`
from business
WHERE SUBSTRING(orderdate,1,7)='2017-04'
group by name ;
-- 2.查詢顧客的購(gòu)買明細(xì)及月購(gòu)買總額
SELECT name ,orderdate ,cost ,
sum (cost) over(partition by MONTH (orderdate))
from business;
-- 3.上述的場(chǎng)景, 將每個(gè)顧客的cost按照日期進(jìn)行累加
SELECT name ,orderdate ,cost ,
sum (cost) over(partition by name order by orderdate)
from business;
4) CURRENT ROW:當(dāng)前行
n PRECEDING:往前n行數(shù)據(jù)
n FOLLOWING:往后n行數(shù)據(jù)
5)UNBOUNDED:起點(diǎn),
UNBOUNDED PRECEDING 表示從前面的起點(diǎn)
UNBOUNDED FOLLOWING 表示到后面的終點(diǎn)
6)LAG(col,n,default_val):往前第n行數(shù)據(jù)
7)LEAD(col,n, default_val):往后第n行數(shù)據(jù)
8)NTILE(n):把有序窗口的行分發(fā)到指定數(shù)據(jù)的組中,各個(gè)組有編號(hào),編號(hào)從1開始,對(duì)于每一行,NTILE返回此行所屬的組的編號(hào)。注意:n必須為int類型。
示例:
-- 需求:查詢前20%時(shí)間的訂單信息
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
from business
) t
where sorted = 1;
6.5 Rank
-- 函數(shù)說明
1) RANK() 排序相同時(shí)會(huì)重復(fù),總數(shù)不會(huì)變;
-- 1 2 2 4 5 5 7
2) DENSE_RANK() 排序相同時(shí)會(huì)重復(fù),總數(shù)會(huì)減少;
-- 1 2 2 3 3 4 4 5
3) ROW_NUMBER() 會(huì)根據(jù)順序計(jì)算。
-- 1 2 3 4 5 6
6.6 自定義函數(shù)
自定函數(shù)的分類:
1) UDF(User-Defined-Function) -- 一進(jìn)一出
2) UDAF(User-Defined Aggregation Function) -- 聚集函數(shù),多進(jìn)一出
類似于:count/max/min
3) UDTF(User-Defined Table-Generating Functions) -- 一進(jìn)多出
如lateral view explode()
6.6.1 自定義UDF函數(shù)
- 需求:UDF實(shí)現(xiàn)計(jì)算給定字符串的長(zhǎng)度
示例:
select my_len("abcd"); ==> 4
- 創(chuàng)建一個(gè)Maven工程
- 導(dǎo)入依賴
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
- 創(chuàng)建一個(gè)類繼承于GenericUDF
package com.lianzp.hive;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
/**
* 自定義UDF函數(shù),需要繼承GenericUDF類
* 需求: 計(jì)算指定字符串的長(zhǎng)度
*/
public class MyStringLength extends GenericUDF {
/**
*
* @param arguments 輸入?yún)?shù)類型的鑒別器對(duì)象
* @return 返回值類型的鑒別器對(duì)象
* @throws UDFArgumentException
*/
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 判斷輸入?yún)?shù)的個(gè)數(shù)
if(arguments.length !=1){
throw new UDFArgumentLengthException("Input Args Length Error!!!");
}
// 判斷輸入?yún)?shù)的類型
if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
throw new UDFArgumentTypeException(0,"Input Args Type Error!!!");
}
//函數(shù)本身返回值為int,需要返回int類型的鑒別器對(duì)象
return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
}
/**
* 函數(shù)的邏輯處理
* @param arguments 輸入的參數(shù)
* @return 返回值
* @throws HiveException
*/
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
if(arguments[0].get() == null){
return 0 ;
}
return arguments[0].get().toString().length();
}
@Override
public String getDisplayString(String[] children) {
return "";
}
}
- 打成jar包上傳到服務(wù)器/opt/module/hive/datas/myudf.jar
- 將jar包添加到hive的classpath
add jar /opt/module/hive/datas/myudf.jar;
- 創(chuàng)建臨時(shí)函數(shù)與開發(fā)好的java class關(guān)聯(lián)
create temporary function my_len as "com.lianzp.hive. MyStringLength";
- 即可在hql中使用自定義的函數(shù)my_len
select ename,my_len(ename) ename_len from emp;
6.6.2 自定義UDTF函數(shù)
和udf的最大區(qū)別就是自定義函數(shù)不同。
package com.lianzp.udtf;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
import java.util.List;
public class MyUDTF extends GenericUDTF {
private ArrayList<String> outList = new ArrayList<>();
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
//1.定義輸出數(shù)據(jù)的列名和類型
List<String> fieldNames = new ArrayList<>();
List<ObjectInspector> fieldOIs = new ArrayList<>();
//2.添加輸出數(shù)據(jù)的列名和類型
fieldNames.add("lineToWord");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}
@Override
public void process(Object[] args) throws HiveException {
//1.獲取原始數(shù)據(jù)
String arg = args[0].toString();
//2.獲取數(shù)據(jù)傳入的第二個(gè)參數(shù),此處為分隔符
String splitKey = args[1].toString();
//3.將原始數(shù)據(jù)按照傳入的分隔符進(jìn)行切分
String[] fields = arg.split(splitKey);
//4.遍歷切分后的結(jié)果,并寫出
for (String field : fields) {
//集合為復(fù)用的,首先清空集合
outList.clear();
//將每一個(gè)單詞添加至集合
outList.add(field);
//將集合內(nèi)容寫出
forward(outList);
}
}
@Override
public void close() throws HiveException {
}
}
七 、 壓縮與存儲(chǔ)
總結(jié)幾點(diǎn):
1)不同存儲(chǔ)格式的存儲(chǔ)文件的大小對(duì)比總結(jié):
ORC > Parquet > textFile
2)存儲(chǔ)文件的查詢速度測(cè)試:基本相差不大。
-- 在實(shí)際的項(xiàng)目開發(fā)當(dāng)中,hive表的數(shù)據(jù)存儲(chǔ)格式一般選擇:orc或parquet;壓縮方式一般選擇snappy,lzo。
壓縮方式:
| 壓縮格式 | 工具 | 算法 | 文件擴(kuò)展名 | 是否可切分 |
|---|---|---|---|---|
| DEFLATE | 無 | DEFLATE | .deflate | 否 |
| Gzip | gzip | DEFLATE | .gz | 否 |
| bzip2 | bzip2 | bzip2 | .bz2 | 是 |
| LZO | lzop | LZO | .lzo | 是 |
| Snappy | 無 | Snappy | .snappy | 否 |
編碼/解碼器:
| 壓縮格式 | 對(duì)應(yīng)的編碼/解碼器 |
|---|---|
| DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
| gzip | org.apache.hadoop.io.compress.GzipCodec |
| bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
| LZO | com.hadoop.compression.lzo.LzopCodec |
| Snappy | org.apache.hadoop.io.compress.SnappyCodec |
壓縮性能的比較:
| 壓縮算法 | 原始文件大小 | 壓縮文件大小 | 壓縮速度 | 解壓速度 |
|---|---|---|---|---|
| gzip | 8.3GB | 1.8GB | 17.5MB/s | 58MB/s |
| bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
| LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
create table log_parquet_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as parquet -- 指明文件的存儲(chǔ)格式
tblproperties("parquet.compression"="SNAPPY"); -- 指明文件的壓縮方式
詳情見老師文檔。
八 、企業(yè)級(jí)優(yōu)化
見老師文檔