1. 程式人生 > >Hive入門及常用指令

Hive入門及常用指令

Hive

最近在公司實習,對hive進行了學習,做了些整理的筆記。

基礎命令

show databases; # 檢視某個資料庫
use 資料庫;      # 進入某個資料庫
show tables;    # 展示所有表
desc 表名;            # 顯示錶結構
show partitions 表名; # 顯示錶名的分割槽
show create table_name;   # 顯示建立表的結構

# 建表語句
# 內部表
use xxdb; create table xxx;
# 建立一個表,結構與其他一樣
create table xxx like xxx;
# 外部表 use xxdb; create external table xxx; # 分割槽表 use xxdb; create external table xxx (l int) partitoned by (d string) # 內外部錶轉化 alter table table_name set TBLPROPROTIES ('EXTERNAL'='TRUE'); # 內部錶轉外部表 alter table table_name set TBLPROPROTIES ('EXTERNAL'='FALSE');# 外部錶轉內部表 # 表結構修改 # 重命名錶 use xxxdb; alter
table table_name rename to new_table_name;
# 增加欄位 alter table table_name add columns (newcol1 int comment ‘新增’); # 修改欄位 alter table table_name change col_name new_col_name new_type; # 刪除欄位(COLUMNS中只放保留的欄位) alter table table_name replace columns (col1 int,col2 string,col3 string); # 刪除表 use xxxdb; drop
table table_name;
# 刪除分割槽 # 注意:若是外部表,則還需要刪除檔案(hadoop fs -rm -r -f hdfspath) alter table table_name drop if exists partitions (d=‘2016-07-01'); # 欄位型別 # tinyint, smallint, int, bigint, float, decimal, boolean, string # 複合資料型別 # struct, array, map

複合資料型別

# array
create table person(name string,work_locations array<string>)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ',';
# 資料
biansutao beijing,shanghai,tianjin,hangzhou
linan changchu,chengdu,wuhan
# 入庫資料
LOAD DATA LOCAL INPATH '/home/hadoop/person.txt' OVERWRITE INTO TABLE person;
select * from person;
# biansutao       ["beijing","shanghai","tianjin","hangzhou"]
# linan           ["changchu","chengdu","wuhan"]

# map
create table score(name string, score map<string,int>)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':';
# 資料
biansutao '數學':80,'語文':89,'英語':95
jobs '語文':60,'數學':80,'英語':99
# 入庫資料
LOAD DATA LOCAL INPATH '/home/hadoop/score.txt' OVERWRITE INTO TABLE score;
select * from score;
# biansutao       {"數學":80,"語文":89,"英語":95}
# jobs            {"語文":60,"數學":80,"英語":99}

# struct
CREATE TABLE test(id int,course struct<course:string,score:int>)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ',';
# 資料
1 english,80
2 math,89
3 chinese,95
# 入庫
LOAD DATA LOCAL INPATH '/home/hadoop/test.txt' OVERWRITE INTO TABLE test;
# 查詢
select * from test;
# 1       {"course":"english","score":80}
# 2       {"course":"math","score":89}
# 3       {"course":"chinese","score":95}

配置優化

# 開啟任務並行執行
set hive.exec.parallel=true
# 設定執行記憶體
set mapreduce.map.memory.mb=1024;
set mapreduce.reduce.memory.mb=1024;
# 指定佇列
set mapreduce.job.queuename=jppkg_high;
# 動態分割槽,為了防止一個reduce處理寫入一個分割槽導致速度嚴重降低,下面需設定為false
# 預設為true
set hive.optimize.sort.dynamic.partition=false;
# 設定變數
set hivevar:factor_timedecay=-0.3;
set hivevar:pre_month=${zdt.addDay(-30).format("yyyy-MM-dd")};
set hivevar:pre_date=${zdt.addDay(-1).format("yyyy-MM-dd")};
set hivevar:cur_date=${zdt.format("yyyy-MM-dd")};
# 新增第三方jar包, 新增臨時函式
add jar ***.jar;
# 壓縮輸出,ORC預設自帶壓縮,不需要額外指定,如果使用非ORCFile,則設定如下
hive.exec.compress.output=true
# 如果一個大檔案可以拆分,為防止一個Map讀取過大的資料,拖慢整體流程,需設定
hive.hadoop.suports.splittable.combineinputformat
# 避免因資料傾斜造成的計算效率,預設false
hive.groupby.skewindata
# 避免因join引起的資料傾斜
hive.optimize.skewjoin
# map中會做部分聚集操作,效率高,但需要更多記憶體
hive.map.aggr   -- 預設開啟
hive.groupby.mapaggr.checkinterval  -- 在Map端進行聚合操作的條目數目
# 當多個group by語句有相同的分組列,則會優化為一個MR任務。預設關閉。
hive.multigroupby.singlemr
# 自動使用索引,預設不開啟,需配合row group index,可以提高計算速度
hive.optimize.index.filter

常用函式

# if 函式,如果滿足條件,則返回A, 否則返回B
if (boolean condition, T A, T B)
# case 條件判斷函式, 當a為b時則返回c;當a為d時,返回e;否則返回f
case a when b then c when d then e else f end
# 將字串型別的資料讀取為json型別,並得到其中的元素key的值
# 第一個引數填寫json物件變數,第二個引數使用$表示json變數標識,然後用.讀取物件或陣列;
get_json_object(string s, '$.key')
# url解析
# parse_url('http://facebook.com/path/p1.php?query=1','HOST')返回'facebook.com' 
# parse_url('http://facebook.com/path/p1.php?query=1','PATH')返回'/path/p1.php' 
# parse_url('http://facebook.com/path/p1.php?query=1','QUERY')返回'query=1',
parse_url()
# explode就是將hive一行中複雜的array或者map結構拆分成多行
explode(colname)
# lateral view 將一行資料adid_list拆分為多行adid後,使用lateral view使之成為一個虛表adTable,使得每行的資料adid與之前的pageid一一對應, 因此最後pageAds表結構已發生改變,增加了一列adid
select pageid, adid from pageAds
lateral view explode(adid_list) adTable as adid
# 去除兩邊空格
trim()
# 大小寫轉換
lower(), upper()
# 返回列表中第一個非空元素,如果所有值都為空,則返回null
coalesce(v1, v2, v3, ...)
# 返回當前時間
from_unixtime(unix_timestamp(), 'yyyy-MM-dd HH:mm:ss')
# 返回第二個引數在待查詢字串中的位置(找不到返回0)
instr(string str, string search_str)
# 字串連線
concat(string A, string B, string C, ...)
# 自定義分隔符sep的字串連線
concat_ws(string sep, string A, string B, string C, ...)
# 返回字串長度
length()
# 反轉字串
reverse()
# 字串擷取
substring(string A, int start, int len)
# 將字串A中的符合java正則表示式pat的部分替換為C;
regexp_replace(string A, string pat, string C)
# 將字串subject按照pattern正則表示式的規則進行拆分,返回index制定的字元
# 0:顯示與之匹配的整個字串, 1:顯示第一個括號裡的, 2:顯示第二個括號裡的
regexp_extract(string subject, string pattern, int index)
# 按照pat字串分割str,返回分割後的字串陣列
split(string str, string pat)
# 型別轉換
cast(expr as type)
# 將字串轉為map, item_pat指定item之間的間隔符號,dict_pat指定鍵與值之間的間隔
str_to_map(string A, string item_pat, string dict_pat)
# 提取出map的key, 返回key的array
map_keys(map m)
# 日期函式
# 日期比較函式,返回相差天數,datediff('${cur_date},d)
    datediff(date1, date2)

HQL和SQL的差異點

# 1 select distinct 後必須指定欄位名
# 2 join 條件僅支援等值關聯且不支援or條件
# 3 子查詢不能在select中使用;
# 4 HQL中沒有UNION,可使用distinct+ union all 實現 UNION;
# 5 HQL以分號分隔,必須在每個語句結尾寫上分號;
# 6 HQL中字串的比較比較嚴格,區分大小寫及空格,因此在比較時建議upper(trim(a))=upper(trim(b))
# 7 日期判斷,建議使用to_date(),如:to_date(orderdate)=‘2016-07-18’
# 8 關鍵字必須在欄位名上加``符號,如select `exchange` from xxdb.xxtb;
# 9 資料庫和表/檢視之間僅有1個點,如xx_db.xx_tb;

# HQL不支援update/delete
# 實際採用union all + left join (is null)變相實現update
# 思路:
# 1 取出增量資料;
# 2 使用昨日分割槽的全量資料通過主鍵左連線增量資料,並且只取增量表中主鍵為空的資料(即,取未發生變化的全量資料);
# 3 合併1、2的資料覆蓋至最新的分割槽,即實現了update;

# HQL delete實現
# 採用not exists/left join(is null)的方法變相實現。
# 1.取出已刪除的主鍵資料(表B);
# 2.使用上一個分割槽的全量資料(表A)通過主鍵左連線A,並且只取A中主鍵為空的資料,然後直接insert overwrite至新的分割槽;

基本概念

# hive
hive是基於hadoop的一個數據倉庫工具,可以將結構化的資料檔案對映為一張資料庫庫表,並提供類SQL查詢功能。
# 基本組成
使用者介面:CLI,shell命令列;JDBC/ODBC是hive的java實現;webGUI是通過瀏覽器訪問hive;
元資料儲存:通常是儲存在關係資料庫如mysql, derby中;hive的元資料包括表的名字,表的列和分割槽及其屬性,表的屬性(是否為外部表),表的資料所在目錄等。
直譯器,編譯器,優化器完成HQL查詢語句從詞法分析,語法分析,編譯,優化以及查詢計劃的生成。生成的查詢儲存在HDFS中,並隨後有mapreduce呼叫執行。
因此,hive與Hadoop的關係可以理解為使用者發出SQL查詢語句,hive將查詢儲存在HDFS中,然後由mapreduce呼叫執行。
# table
Hive 中的 Table 和資料庫中的 Table 在概念上是類似的,每一個 Table 在 Hive 中都有一個相應的目錄儲存資料。例如,一個表 pvs,它在 HDFS 中的路徑為:/wh/pvs,其中,wh 是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的資料倉庫的目錄,所有的 Table 資料(不包括 External Table)都儲存在這個目錄中。
# partition
Partition 對應於資料庫中的 Partition 列的密集索引,但是 Hive 中 Partition 的組織方式和資料庫中的很不相同。在 Hive 中,表中的一個 Partition 對應於表下的一個目錄,所有的 Partition 的資料都儲存在對應的目錄中。例如:pvs 表中包含 ds 和 city 兩個 Partition,則對應於 ds = 20090801, ctry = US 的 HDFS 子目錄為:/wh/pvs/ds=20090801/ctry=US;對應於 ds = 20090801, ctry = CA 的 HDFS 子目錄為;/wh/pvs/ds=20090801/ctry=CA
# buckets
Buckets 對指定列計算 hash,根據 hash 值切分資料,目的是為了並行,每一個 Bucket 對應一個檔案。將 user 列分散至 32 個 bucket,首先對 user 列的值計算 hash,對應 hash 值為 0 的 HDFS 目錄為:/wh/pvs/ds=20090801/ctry=US/part-00000;hash 值為 20 的 HDFS 目錄為:/wh/pvs/ds=20090801/ctry=US/part-00020
# external table
External Table 指向已經在 HDFS 中存在的資料,可以建立 Partition。它和 Table 在元資料的組織上是相同的,而實際資料的儲存則有較大的差異。
Table 的建立過程和資料載入過程(這兩個過程可以在同一個語句中完成),在載入資料的過程中,實際資料會被移動到資料倉庫目錄中;之後對資料對訪問將會直接在資料倉庫目錄中完成。刪除表時,表中的資料和元資料將會被同時刪除。
External Table 只有一個過程,載入資料和建立表同時完成(CREATE EXTERNAL TABLE ……LOCATION),實際資料是儲存在 LOCATION 後面指定的 HDFS 路徑中,並不會移動到資料倉庫目錄中。當刪除一個 External Table 時,僅刪除元資料,表中的資料不會真正被刪除。
# 全量資料和增量資料
檢視分割槽資訊
如果分割槽的大小隨時間增加而增加,則最新的分割槽為全量資料
如果分割槽的大小隨時間增加而大小上下變化,則每個分割槽都是增量資料

實際使用

# 增加分割槽
insert overwrite table table_name partition (d='${pre_date}')

# 建表語句
# 進行分割槽,每個分割槽相當於是一個資料夾,如果是雙分割槽,則第二個分割槽作為第一個分割槽的子資料夾
drop table if exists employees;  
create table  if not exists employees(  
       name string,  
       salary float,  
       subordinate array<string>,  
       deductions map<string,float>,  
       address struct<street:string,city:string,num:int>  
) partitioned by (date_time string, type string)
row format delimited
fields terminated by '\t'
collection items terminated by ','
map keys terminated by ':'
lines terminated by '\n'
stored as textfile
location '/hive/...';

# hive桶
# 分割槽是粗粒度的,桶是細粒度的
# hive針對某一列進行分桶,對列值雜湊,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶中
create table bucketed_user(id int, name string)
clustered by (id) sorted by (name) into 4 buckets
row format delimited
fields terminated by '\t'
stored as textfile;
# 注意,使用桶表的時候我們要開啟桶表
set hive.enforce.bucketing=true;
# 將employee表中的name和salary查詢出來插入到表中
insert overwrite table bucketed_user select salary, name from employees

如果欄位型別是string,則通過get_json_object提取資料;
如果欄位型別是struct或map,則通過col['xx']方式提取資料;

shell指令

#!/bin/bash
hive -e "use xxxdb;"

cnt = `hive -e "..."`
echo "cnt=${cnt}"

# 迴圈語句
for ((i=1; i<=10; i+=1))
do
pre_date=`date -d -${i}days +%F`
done

# 定義日期
pre_date=`date -d -1days +%F`
pre_week=`date -d -7days +%F`

# 設定環境變數
export JAVA_HOME=jdk;

References: