1 數據庫
(1)創建數據庫
CREATE DATABASE [IF NOT EXISTS] financials;
(2)查看數據庫列表
SHOW DATABASES;
SHOW DATABASES LIKE ‘h.*’;
(3)查看數據庫的描述
DESCRIBE DATABASE financials;
(4)修改數據庫
ALTER DATABASE financials SET DBPROPERTIES (’ edi ted-by’ = ‘Joe Dba’ ) ;
(5)刪除數據庫
DROP DATABASE IF EXISTS financials;
2 表
2.1 託管表和外部表
2.1.1 託管表
把HDFS中的數據移動到Hive的倉庫中,數據由Hive管理。
(1)創建表
① 創建一個新表
CREATE TABLE records (year STRING, temperature INT, quality INT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
② 創建一個與一個存在的表的模式相同的表
CREATE TABLE new_table LIKE existing_table;
(2)加載數據
LOAD DATA LOCAL INPATH 'input/ncdc/micro-tab/sample.txt' OVERWRITE INTO TABLE records;
注:當數據被加載至表中時,不會對數據進行任何轉換。Load 操作只是將數據複製/移動至 Hive 表對應的位置。
(3)查詢每個年份最大的溫度
SELECT year, MAX(temperature) FROM records WHERE
temperature != 9999 AND quality IN (0, 1, 4, 5, 9) GROUP BY year;
(4)查看錶
SHOW TABLES;
(5)修改表
① 重命名
ALTER TABLE records RENAME TO records2;
② 修改列的信息
ALTER TABLE users CHANGE COLUM name names STRING COMMENT 'change names' [AFTER 子句];
③ 增加列
ALTER TABLE users ADD COLUMNS (col3 STRING);
(6)表的刪除
① 刪除表中所有的數據,保留表的定義
TRUNCATE TABLE users;
② 連同數據和元數據一起刪除
DROP TABLE users;
2.1.2 外部表
外部數據由HDFS管理,並不會將外部數據移動到Hive的倉庫中。
(1)創建表‘’
CREATE EXTERNAL TABLE external_table (dummy STRING) LOCATION '/user/tom/external_table';
LOCATION 後面是HDFS地址。
2.2 分區和桶
2.2.1 分區
(1)簡介
分區表是指在創建表的時候指定的partition的分區空間,這樣在查找分區的數據時,就不用掃描所有數據文件,只需要掃描指定分區的數據文件。
(2)細節
① 分區表依據分區列的值對錶進行劃分,每個分區對應表的子目錄,所有數據依照分區列放入不同的子目錄中;
② 分區列是以字段的形式在表結構中存在,可以通過describe table命令查看到字段存在,但是分區字段不存放實際的數據內容,僅僅是分區的表示。
(3)優點
① 分區可以縮小查詢範圍,加快數據的檢索速度;
② 便於數據管理,常見日期分區,業務分區等。
(4)創建分區表
CREATE TABLE logs (ts BIGINT, line STRING) PARTITIONED BY (dt STRING, country STRING);
(5)加載數據到分區表
LOAD DATA LOCAL INPATH 'input/hive/partitions/file1' INTO TABLE
logs PARTITION (dt='2001-01-01', country='GB');
(6)查詢關於GB國家的記錄
·SELECT ts, dt, line FROM logs WHERE country='GB';
(7)查看分區
SHOW PARTITIONS logs;
(8)修改分區
① 添加分區
ALTER TABLE logs ADD IF NOT EXISTS PARTITION (dt='2001-01-03', country='GB')
LOCATION ‘/input/hive/pastitions/file7’;
② 修改分區
ALTER TABLE logs PARTITION (dt='2001-01-03', country='GB') SET
LOCATION ‘/input/hive/pastitions/file8’
③ 刪除分區
ALTER TABLE logs DROP IF NOT EXISTS PARTITION (dt='2001-01-03', country='GB');
2.2.2 桶
(1)簡介
對於每一個Hive表(包括分區表),Hive可以進一步對數據進行分桶,桶是更細粒度的數據範圍劃分。分區是針對文件目錄,分桶則是針對數據文件。桶是通過對指定列進行哈希計算來實現的,通過哈希值將一個列名下的數據切分爲一組桶,對哈希值除以桶的個數求餘數的方式決定該記錄存放在哪個桶中,每個桶對應於該列名下的一個存儲文件。
(2)優點
① 更高的查詢效率;
② 連接兩個在(包含連接列的)相同的列上劃分了桶的表,可以使用map端連接(map-side join)高效地實現;即當需要關聯的表的列上都做了分桶,會有更高的連接效率;
③ 取樣或採樣更高效。
(3)注意
① 當前不支持對已有的表進行分桶,只能新建分桶表,然後倒入數據;
② 需加入設置自動分桶:set hive.enforce.bucketing = true。
(4)創建分桶表
CREATE TABLE bucketed_users (id INT, name STRING) CLUSTERED BY (id)
SORTED BY (id ASC) INTO 4 BUCKETS;
ASC:升序
(5)插入數據
INSERT OVERWRITE TABLE bucketed_users SELECT * FROM users;
(6)查詢數據
① 查詢1/4的數據
SELECT * FROM bucketed_users TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);
② 查詢1/2的數據
SELECT * FROM bucketed_users TABLESAMPLE(BUCKET 1 OUT OF 2 ON id);
③ 隨機讀取小部分數據
SELECT * FROM users TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand());
3 存儲格式
Hive從兩個維度對錶的存儲進行管理,分別是行格式和文件格式。
行格式指行和一行中的字段如何存儲。行格式由SerDe定義。SerDe是“序列化和反序列化”的合成詞。當作爲反序列化工具進行使用時,也就是查詢表時,SerDe 將把文件中字節形式的數據行反序列化爲Hive 內部操作數據行時所使用的對象形式。使用序列化工具時,也就是執行INSERT或CTAS時,表的SerDe會把Hive 的數據行內部表示形式序列化成字節形式並寫到輸出文件中。
文件格式指一行中字段容器的格式。最簡單的格式純文本格式,但是也可以使用面向行的和麪向列的二進制格式。
3.1 默認存儲格式:分隔的文本
(1)沒有使用ROW FORMAT或STORED AS子句,默認格式爲分隔的文本,每行存儲一個數據行。
(2)默認的行內分隔符不是製表符,而是ASCII控制碼集合中的Control-A(它的ASCII碼爲1)。
(3)Hive無法對分隔符轉義,因此挑選一個不會在數據字段中用到的字符作爲分隔符尤爲重要。
(4)集合類元素的默認分隔符爲字符Control-B,它用於分隔ARRAY或STRUCT或MAP的鍵值對中的元素。默認的鍵值對分隔符爲Control-C。
(5)各行之間用換行符分隔。
(6)Hive內部有一個LazySimpleSerDe的SerDe來處理分割格式和麪向行的MapReduce文本輸入和輸出格式。“Lazy”的原因是這個SerDe對字段的反序列化是延遲處理的,只有在訪問字段時才進行序列化。
3.2 二進制存儲格式:順序文件、Avro數據文件、Parquet文件、RCFile與ORCFile
二進制格式可分爲兩大類:面向行的格式和麪向列的格式。面向列的格式對於那些只訪問表中一小部分列的查詢邊角有效。面向行的格式適合同時處理一行中很多列的情況。
(1)通過CREATE TABLE語句中的STORED AS子句做相應聲明。不需要指定ROW FORMAT,因爲其格式由底層的二進制文件格式來控制。
(2)創建表時指定存儲格式
以Parquet文件存儲格式爲例
CREATE TABLE users_parquet STORED AS PARQUET AS SELECT * FROM users;
3.3 使用定製的SerDe: RegexSerDe
CREATE TABLE stations (usaf STRING, wban STRING, name STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "(\\d{6}) (\\d{5}) (.{29}) .*"
);
(1)ROW FORMAT 子句中使用DELIMITED 關鍵字來說明文本是如何分隔的。
(2)用SERDE關鍵字和用到的java完整類名來指明使用哪個SerDe。
(3)WITH SERDEPROPERTIES子句來設置額外的屬性。
(4)input.regex是在反序列化期間將要使用的正則表達式模式。用來將數據行中的部分文本轉化爲列的集合。這個示例中,有三個捕獲組:usaf(六位數的標識符)、wban(五位數的標識符)以及name(29個字符的定長列)。
(5)有時,可能要在正則表達式中使用括號,而不希望這些括號被當作捕獲所用的符號。例如,模式(ab)+可用於匹配一個或多個連續的ab 字符串。這時的解決辦怯是在左括號後加問號?表示"非捕獲組"(noncapturing group)。用(?ab)+來避免某個文本序列被捕獲。
(6)RegexSerDe的效率非常低,因此一般不用於通用存儲格式,應當考慮把數據複製爲二進制存儲格式。
3.4 存儲句柄
用於Hive無法訪問的存儲系統,比如HBase。使用STORED BY子句指定。它代替了ROW FORMAT和STORED AS子句。
CREATE TABLE hbase_table_1(key int, value1 string, value2 int, value3 int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ( "hbase.columns.mapping" = ":key,a:b,a:c,d:e" );
4 導入數據
(1)INSERT語句
① 插入數據
INSERT OVERWRITE TABLE target SELECT col1, col2 FROM source;
INSERT OVERWRITE TABLE target PARTITION (dt='2001-01-01') SELECT col1, col2 FROM source;
OVERWRITE 關鍵字意味着目標表(對於前面的第一個例子)或2001-01-01 分區(對於第二個例子)中的內容會被SELECT 語句的結果替換掉。
② 動態插入數據
INSERT OVERWRITE TABLE target PARTITION (dt) SELECT col1, col2, dt FROM source;
(2)多表插入
多表插入(multitable insert)比使用多個單獨的INSERT 語句效率更高,因爲只需要掃描一遍源表就可以生成多個不相交的輸出。
FROM records2
INSERT OVERWRITE TABLE stations_by_year
SELECT year, COUNT(DISTINCT station)
GROUP BY year
INSERT OVERWRITE TABLE records_by_year
SELECT year, COUNT(1)
GROUP BY year
INSERT OVERWRITE TABLE good_records_by_year
SELECT year, COUNT(1)
WHERE temperature != 9999 AND quality IN (0, 1, 4, 5, 9)
GROUP BY year;
(3)CREATE TABLE…AS SELECT語句
CREATE TABLE target AS SELECT col1, col2 FROM source;
CTAS操作是原子的。失敗,就不會創建新表。
5 查詢數據
5.1 排序和聚集
(1)order by
① 啓動一個reduce task;
② 數據全局有序;
③ 速度可能會非常慢;
④ Strict模式下,必須與limit連用。
(2)sort by
① 可以有多個reduce task;
② 每個Reduce Task內部數據有序,但全局無序;
③ 通常與distribute by。
(3)distribute by
① 相當於MapReduce中的paritioner,默認是基於hash實現的;
② 與sort by連用,可發揮很好的作用。
③ 舉例:SELECT s.ymd,s.symbol,s.price_close FROM stocks s DISTRIBUTE BY s.symbol SORT BY s.symbol ASC,s.ymd ASC;
(4)cluster by
① 當distribute by與sort by連用,且跟隨的字段相同時,可使用cluster by簡寫;
② 舉例:SELECT s.ymd,s.symbol,s.price_close FROM stocks s CLUSTER BY s.symbol;
5.2 MapReduce腳本
(1)Python 代碼
① Map
import re
import sys
for line in sys.stdin:
(year, temp, q) = line.strip().split()
if (temp != "9999" and re.match("[01459]", q)):
print "%s\t%s" % (year, temp)
② Reduce
import sys
(last_key, max_val) = (None, -sys.maxint)
for line in sys.stdin:
(key, val) = line.strip().split("\t")
if last_key and last_key != key:
print "%s\t%s" % (last_key, max_val)
(last_key, max_val) = (key, int(val))
else:
(last_key, max_val) = (key, max(max_val, int(val)))
if last_key:
print "%s\t%s" % (last_key, max_val)
(2)Hive腳本
① 使用SELECT TRANSFORM查詢符合條件的記錄
ADD FILE /src/main/python/is_good_quality.py;
FROM records
SELECT TRANSFORM(year, temperature, quality)
USING 'is_good_quality.py'
AS year, temperature;
② 使用MAP和REDUCE查詢每年最高氣溫
FROM (
FROM records2
MAP year, temperature, quality
USING 'is_good_quality.py'
AS year, temperature) map_output
REDUCE year, temperature
USING 'max_temperature_reduce.py'
AS year, temperature;
5.3 連接
Hive不僅支持等值連接,還支持非等值連接。
hive> SELECT * FROM sales;
Joe 2
Hank 4
Ali 0
Eve 3
Hank 2
hive> SELECT * FROM things;
2 Tie
4 Coat
3 Hat
1 Scarf
(1)內連接
hive> SELECT sales.*, things.*
> FROM sales JOIN things ON (sales.id = things.id);
Joe 2 2 Tie
Hank 4 4 Coat
Eve 3 3 Hat
Hank 2 2 Tie
(2)外連接
① 左外連接
hive> SELECT sales.*, things.*
> FROM sales LEFT OUTER JOIN things ON (sales.id = things.id);
Joe 2 2 Tie
Hank 4 4 Coat
Ali 0 NULL NULL
Eve 3 3 Hat
Hank 2 2 Tie
② 右外連接
hive> SELECT sales.*, things.*
> FROM sales RIGHT OUTER JOIN things ON (sales.id = things.id);
Joe 2 2 Tie
Hank 2 2 Tie
Hank 4 4 Coat
Eve 3 3 Hat
NULL NULL 1 Scarf
③ 全外連接
hive> SELECT sales.*, things.*
> FROM sales FULL OUTER JOIN things ON (sales.id = things.id);
Ali 0 NULL NULL
NULL NULL 1 Scarf
Hank 2 2 Tie
Joe 2 2 Tie
Eve 3 3 Hat
Hank 4 4 Coat
(3)半連接
① 左半連接
hive> SELECT * FROM things LEFT SEMI JOIN sales ON (sales.id = things.id);
2 Tie
4 Coat
3 Hat
(4)map連接
1) Map-side Join(Broadcast join)
對於普通的join操作,會在map端根據key的hash值,shuffle到某一個reduce上去,在reduce端做join連接操作,內存中緩存join左邊的表,遍歷右邊的表,依次做join操作。所以在做join操作時候,將數據量多的表放在join的右邊。當數據量比較大,並且key分佈不均勻,大量的key都shuffle到一個reduce上了,就出現了數據傾斜。解決方法:在進行兩個表join的過程中,由於hive都是從左向右執行,要注意講小表在前,大表在後(小表會先進行緩存)即Map join解決數據傾斜。
① Join操作在map task中完成,因此無需啓動reduce task;
② 適合一個大表,一個小表的連接操作;
③ 思想:小表複製到各個節點上,並加載到內存中;大表分片,與小表完成連接操作。
④ 舉例:select /*+ mapjoin(A)*/ f.a,f.b from A t join B f on ( f.a=t.a);
2)Reduce-side Join(shuffle join)
① Join操作在reduce task中完成;
② 適合兩個大表連接操作;
③ 同一個key對應的字段可能位於不同map中。Reduce-side join是非常低效的,因爲shuffle階段要進行大量的數據傳輸;
③ 思想:map端按照連接字段進行hash,reduce 端完成連接操作。
5.4子查詢(只支持不相關子查詢)
SELECT station, year, AVG(max_temperature)
FROM (
SELECT station, year, MAX(temperature) AS max_temperature
FROM records2
WHERE temperature != 9999 AND quality IN (0, 1, 4, 5, 9)
GROUP BY station, year
) mt
GROUP BY station, year;
5.5視圖
CREATE VIEW valid_records
AS
SELECT *
FROM records2
WHERE temperature != 9999 AND quality IN (0, 1, 4, 5, 9);
(1)視圖是由從數據庫的基本表中選取出來的數據組成的邏輯窗口,與基本表不同,它是一個虛表。
(2)視圖可以被定義爲多個表的連接,也可以被定義爲只有部分列可見,也可爲部分行可見。
(3)在數據庫中,存放的只是視圖的定義,而不存放視圖包含的數據項,這些項目仍然存放在原來的基本表結構中。所以說視圖是基於表來創建得到的視圖。
(4)視圖是隻讀的,不能向視圖中插入或是加載數據。
(5)視圖的作用:① 可以簡化數據查詢語句;② 可以使用戶能從多角度看待同一數據;③ 通過引入視圖可以提高數據的安全性; ④ 視圖提提供了一定程度的邏輯獨立性等。
(6)視圖機制的好處:① 通過引入視圖機制,用戶可以將注意力集中在其關心的數據上(而非全部數據),這樣就大大提高了用戶效率與用戶滿意度,而且如果這些數據來源於多個基本表結構,或者數據不僅來自於基本表結構,還有一部分數據來源於其他視圖,並且搜索條件又比較複雜時,需要編寫的查詢語句就會比較煩瑣,此時定義視圖就可以使數據的查詢語句變得簡單可行;② 定義視圖可以將表與表之間的複雜的操作連接和搜索條件對用戶不可見,用戶只需要簡單地對一個視圖進行查詢即可,故增加了數據的安全性,但不能提高查詢效率。
6 用戶定義函數(必須使用Java語言編寫)
擴展HQL能力的一種方式。
(1)普通UDF
UDF 操作作用於單個數據行,且產生一個數據行作爲輸出(1對1)。大多數函數(例如數學函數和字符串函數)都屬於這一類。
(2)用戶定義聚集函數(user-defined aggregate function,UDAF)
UDAF 接受多個輸入數據行,併產生一個輸出數據行(多對1)。像COUNT 和MAX這樣的函數都是聚集函數。
(3)用戶定義表生成函數(user-defined table-generating function , UDTF)
UDTF 操作作用於單個數據行,且產生多個數據行(即一個表)作爲輸出(1對多)。
7 Hive Streaming操作值python
(1)安裝包
pip3 install sasl
(若失敗,離線安裝,資源下載地址https://www.lfd.uci.edu/~gohlke/pythonlibs/#sasl)
pip3 install thrift
pip3 install thrift-sasl
pip3 install PyHive
(2)python代碼
from pyhive import hive
# host主機ip,port:端口號,username:用戶名,database:使用的數據庫名稱
conn = hive.Connection(host='192.168.1.120',port=10000,
username='hadoop',database='financials',auth='NOSASL')
cursor=conn.cursor()
cursor.execute('select * from logs limit 10')
for result in cursor.fetchall():
print (result)
(3)遇到的問題
① Connection Issue: thrift.transport.TTransport.TTransportException: TSocket read 0 bytes
將hive-site.xml添加
<property>
<name>hive.server2.authentication</name>
<value>NOSASL</value>
<description>
Expects one of [nosasl, none, ldap, kerberos, pam, custom].
Client authentication types.
NONE: no authentication check
LDAP: LDAP/AD based authentication
KERBEROS: Kerberos/GSSAPI authentication
CUSTOM: Custom authentication provider
(Use with property hive.server2.custom.authentication.class)
PAM: Pluggable authentication module
NOSASL: Raw transport
</description>
</property>
② hadoop is not allowed to impersonate hadoop (state=08S01,code=0)
在core-site.xml添加
<property>
<name>hadoop.proxyuser.hadoop.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hadoop.groups</name>
<value>*</value>
</property>
③ 默認情況下,HiveServer2以提交查詢的用戶執行查詢訪問(true),如果hive.server2.enable.doAs設置爲false,查詢將以運行hiveserver2進程的用戶訪問。在hive-site.xml添加
<property>
<name>hive.server2.enable.doAs</name>
<value>true</value>
</property>
參考文章:
[1] https://www.jianshu.com/p/3ce51432981a
[2] https://www.cnblogs.com/wenBlog/archive/2019/02/11/10361404.html
[3] https://www.cnblogs.com/zlslch/p/6105243.html
[4]《Hadoop權威指南》
[5]《Hive編程指南》