Hive - 總結(jié)

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)原理

image.png
-- 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ì)算性能。
image-20200720001521940

一、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)化

  1. 隱式類型轉(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)換為任何其它的類型。

  1. 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ù)說明:

  1. EXTERNAL :表示外部表,在刪除表時(shí),只會(huì)刪除mysql中的元數(shù)據(jù),在hdfs的真實(shí)數(shù)據(jù)不會(huì)被刪除,如果沒EXTERNAL ,則刪除表的時(shí)候,元數(shù)據(jù)和真實(shí)數(shù)據(jù)均為被刪除。

  2. IF NOT EXISTS :當(dāng)表存在時(shí),添加此操作,則不會(huì)拋異常,同時(shí)也不會(huì)執(zhí)行建表操作。

  3. COMMENT :字段或表的注釋;

  4. PARTITIONED BY : 分區(qū)(后面詳細(xì)講);

  5. CLUSTERED BY : 分桶(后面詳細(xì)講);

  6. SORTED BY :文件在hdfs的存儲(chǔ)格式 ,存儲(chǔ)的方式有:SEQUENCEFILE(二進(jìn)制序列文件)、TEXTFILE(文本)、RCFILE(列式存儲(chǔ)格式文件)

    如果文件數(shù)據(jù)是純文本,可以使用STORED AS TEXTFILE。如果數(shù)據(jù)需要壓縮,使用 STORED AS SEQUENCEFILE;

  7. ROW FORMAT row_format :列分割符;

  8. LOCATION hdfs_path:指定表在HDFS上的存儲(chǔ)位置;默認(rèn)為當(dāng)前庫下。

  9. 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 修改表

  1. 重命名表
-- 語法:
alter table 舊表名 rename to 新表名 ;
-- 示例:
alter table dept_partition2 rename to dept_partition3;
  1. 更新列
-- 語法:
alter table 表名 change 舊列名 新列名 數(shù)據(jù)類型  
-- 示例:
alter table emp change ename naem string first deptno;
  1. 增加列
-- 語法:
alter table 表名 add 列名 數(shù)據(jù)類型 [字段注釋] [first / after  列名]
-- 示例:
alter table emp add loc string ;
  1. 刪除表
-- 語法:
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ū)表的基本操作

  1. 創(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'
  1. 加載數(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');

  1. 根據(jù)分區(qū)進(jìn)行查詢
-- 語法:
查詢語句 + where 分區(qū)字段='***' ;

-- 示例:
select  * from dept_partition where day='04' or day='05' ;
  1. 增加分區(qū)
-- 語法:
alter table 表名 add partition (字段1="***",字段2='***')  partition  (字段1="***",字段2='***');
-- 說明:
增加多個(gè)分區(qū)時(shí),分區(qū)與分區(qū)之間使用空格隔開。
  1. 刪除分區(qū)
-- 語法:
alter table 表名 drop partition (字段1="***",字段2='***') , partition  (字段1="***",字段2='***');
-- 說明:
刪除的多個(gè)分區(qū)之間使用','進(jìn)行分隔。
  1. 查看多個(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ū)。
  1. 前期的準(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
  1. 實(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è)寫的表名

image-20200630212310025
image-20200630212550900

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ù)

  1. 需求:UDF實(shí)現(xiàn)計(jì)算給定字符串的長(zhǎng)度
示例:
select my_len("abcd"); ==> 4 
  1. 創(chuàng)建一個(gè)Maven工程
  2. 導(dǎo)入依賴
<dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
</dependencies>
  1. 創(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 "";
    }
}
  1. 打成jar包上傳到服務(wù)器/opt/module/hive/datas/myudf.jar
  2. 將jar包添加到hive的classpath
add jar /opt/module/hive/datas/myudf.jar;
  1. 創(chuàng)建臨時(shí)函數(shù)與開發(fā)好的java class關(guān)聯(lián)
create temporary function my_len as "com.lianzp.hive. MyStringLength";
  1. 即可在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)化

見老師文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容