Hive學習筆記(3)

Hive學習筆記

筆記內容主要來自Hive編程指南

HiveQL:查詢

SELECT…FROM語句

SELECT 是 SQL中的射影算子。FROM子句標識了從哪個表、視圖或嵌套查詢中選擇記錄。

--分區 employees 表
CREATE TABLE employees(
    name            STRING,
    salary          FLOAT,
    subordinates    ARRAY<STRING>,
    deductions      MAP<STRING, FLOAT>,
    address         STRUCT<street:STRING, city:STRING, state STRING>
)
PARTITIONED BY (country STRING, state STRING);

用戶選擇的列是集合數據類型時,Hive會使用JSON語法應用於輸出

-- 選取 ARRAY<STRING> 類型
SELECT name, subordinates FROM employees;

Array類型

-- 選取 MAP<STRING, FLOAT> 類型
SELECT name, deductions FROM employees;

Map類型

-- 選取 STRUCT 類型
SELECT name, address FROM employees;

Struct類型

-- 選取 ARRAY 類型的第 N 個元素
-- 引用一個不存在的元素將返回NULL
SELECT name, subordinates[0] FROM employees;

獲取數組元素

-- 選取 MAP 類型
SELECT name, deductions["State Taxes"] FROM employees;

map類型

-- 選取 MAP 類型
SELECT name, address.city FROM employees;

Struct類型

-- 使用正則表達式來指定列
SELECT symbol,'price.*' FROM stocks;

--使用列值進行計算
SELECT upper(name), salary, deductions["Federal Taxes"], round(salary*(1-deductions["Federal Taxes"])) FROM employees;

算數運算符

算數運算符

使用函數

數學函數

數學函數表1
數學函數表2
數學函數表3

聚合函數

聚合函數1
聚合函數2

-- 設置屬性值爲true來提高聚合的性能
SET hive.map.aggr=true; 

-- HIVE中 不允許在一個查詢語句中使用多於一個的函數(DISTINCT...)
SELECT count(DISTINCT ymd),count(DISTINCT volume) FROM stocks;
表生成函數
-- 數組拆分
SELECT explode(subordinates) AS sub FROM employees;

表生成函數

其他內置函數

內置函數表1
內置函數表2
內置函數表3
內置函數表4
內置函數表5

LIMIT 語句
-- LIMIT...
SELECT upper(name), salary, deduction["Federal Taxes"], round(salary * (1 - deduction["Federal Taxes"]) FROM employees LIMIT 2;
列別名
-- 列別名 使用 AS 關鍵字
SELECT upper(name), salary, deduction["Federal Taxes"] as fed_taxes, round(salary * (1 - deduction["Federal Taxes"]) as salary_minus_fed_taxes 
FROM employees 
LIMIT 2;
嵌套 SELECT 語句
-- 嵌套查詢
FROM (
    SELECT upper(name), salary, deduction["Federal Taxes"] as fed_taxes, round(salary * (1 - deduction["Federal Taxes"]) as salary_minus_fed_taxes 
    FROM employee
) e 
SELECT e.name, e.salary minus_fed_taxes
WHERE e.salary_minus_fed_taxes > 70000;
CASE…WHEN…THEN 句式
-- 用於處理單個列的查詢結果
SELECT name, salary,
    CASE
        WHEN salary < 50000.0 THEN 'low'
        WHEN salary >=50000.0 AND salary < 70000.0 THEN 'middle'
        WHEN salary >=70000.0 AND salary <100000.0 THEN 'high'
        ELSE 'very high'
    END AS bracket FROM employees;
什麼情況下 Hive 可以避免進行MapReduce
-- 本地模式不需要mr過程
SELECT * FROM employees;

-- 對於WHERE 語句中過濾條件只是分區字段這種情況(無論是否使用LIMIT語句限制輸出記錄條數),無需MapReduce過程
SELECT * FROM employees
WHERE country='US' AND state='CA'
LIMIT 100;

-- 如果屬性hive.exec.mode.local.auto 的值爲true,Hive還會嘗試使用本地模式執行其他操作。

WHERE 語句

SELECT 語句用於選取字段, WHERE 語句用於過濾字段

謂詞操作符

謂詞操作符

關於浮點數的比較

對浮點數進行比較時,需要保持極端謹慎的態度。要避免任何從窄類型隱式轉換到更廣泛類型的操作。

LIKE和RLIKE

-- LIKE 標準SQL操作符。
SELECT name, address.street 
FROM employees WHERE address.city LIKE 'O%';

-- RLIKE 子句是 Hive 中這個功能的一個擴展,可以通過Java的正則表達式來指定匹配條件
SELECT name, address.street 
FROM employees 
WHERE address.street RLIKE '.*(Chicago|Ontario).*';

GROUP BY 語句

-- GROUP BY 分組語句
SELECT year(ymd), avg(price_close) FROM stocks
WHERE exchange = 'NASDAQ' AND symbol = 'AAPL'
GROUP BY year(ymd);

-- HAVING 分組後,條件過濾子句。
SELECT year(ymd), avg(price_close) FROM stocks
WHERE exchange = 'NASDAQ' AND symbol = 'AAPL'
GROUP BY year(ymd)
HAVING avg(price_close) >50.0;

JOIN 語句

INNER JOIN
-- 內連接(INNER JOIN)中,只有進行連接的兩個表中都存在與連接標準相匹配的數據纔會被保留下來。

SELECT a.ymd, a.price_close, b.price_close
FROM stocks a JOIN stocks b ON a.ymd = b.ymd
WHERE a.symbol = 'AAPL' AND  b.symbol = 'IBM';

-- ON a.ymd <= b.ymd 這種標準SQL支持的非等值連接,在Hive中是非法的,主要原因是通過MapReduce 很難實現這種類型的連接
-- Hive 目前還不支持在 ON 子句中的謂詞間使用 OR
-- Hive 總是按照從左到右的順序執行的
JOIN 優化

當對3個或更多個表進行JOIN連接時,如果每個ON子句都使用相同的連接鍵的話,那麼只會產生一個 MapReduce job

-- Hive 同時假定查詢中最後一個表是最大的那個表。在對每行記錄進行連接操作時,它會嘗試將其他表緩存起來,然後掃描最後的那個表進行計算。因此,用戶需要保證連續查詢中的表的大小從左到右是依次增加的

-- 錯誤地將最小的表dividends放在了最後面(假定stocks是大表)
SELECT s.ymd, s.symbol, s.price_close, d.dividend
FROM stocks s JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';

-- 應該交換下表stocks和表dividends的位置
SELECT s.ymd, s.symbol, s.price_close, d.dividend
FROM dividends d JOIN stocks s ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';

-- Hive 提供了一個 "標記" 機制來顯示地告知查詢優化器哪張表是大表
SELECT /*+STREAMTABLE(s) */ s.ymd, s.price_close, d.dividend
FROM stocks s JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';
LEFT OUTER JOIN
-- 左外連接通過關鍵字 LEFT OUTER 進行標識
-- JOIN 操作符左邊表中符合 WHERE 子句的所有記錄將會被返回
-- JOIN 操作符右邊表中如果沒有符合 ON 後面連接條件的記錄時, 那麼從右邊表指定選擇的列的值將會是NULL

SELECT s.ymd, s.symbol, s.price_close, d.dividend
FROM stocks s LEFT OUTER JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol = 'AAPL';
OUTER JOIN

OUTER JOIN 語句 先執行 JOIN 語句,然後再將結果通過WHERE 語句進行過濾。
WHERE 語句在連接操作執行後纔會執行,因此WHERE 語句應該只用於過濾那些非NULL值的列值。同時,和Hive的文檔說明中相反的是,ON語句中的分區過濾條件外連接(OUTER JOIN)中是無效的,不過在內連接(INNTER JOIN) 中是有效的。

RIGHT OUTER JOIN
-- 右外連接(RIGHT OUTER JOIN)會返回右邊表所有符合WHERE語句的記錄。左表中匹配不上的字段值用NULL代替。
SELECT a.ymd, s.symbol, s.price_close, d.dividend
FROM dividends d OUTER JOIN stocks s ON d.ymd = s.ymd  AND d.symbol = s.symbol
WHERE s.symbol = 'AAPL';
FULL OUTER JOIN
-- 完全外連接(FULL OUTER JOIN)將會返回所有表中符合WHERE語句條件的所有記錄。如果任一表的指定字段沒有符合條件的值的話,那麼就使用NULL值替代
SELECT s.ymd, s.symbol, s.price_close, d.dividend 
FROM dividends d FULL OUTER JOIN stocks s ON d.ymd = s.ymd AND d.symbol = s.symbol
WHERE s.symbol = 'AAPL';
LEFT SEMI-JOIN
-- 左半開連接(LEFT SEMI-JOIN)會返回左邊表的記錄,前提是其記錄對於右邊表滿足 ON 語句中的判斷條件。
SELECT s.ymd, s.symbol, s.price_close 
FROM stocks s LEFT SEMI JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol;

-- SELECT 和 WHERE 語句中不能引用到右邊表中的字段
-- Hive 不支持右半開連接
笛卡爾積 JOIN

笛卡爾積在一些情況下是很有用的。例如,假設有一個表表示用戶偏好,另有一個表表示新聞文章,同時有一個算法會推測出用戶可能會喜歡讀哪些文章。這個時候就需要使用笛卡爾積生成所有用戶和所有網頁的對應關係和集合。

-- 笛卡爾積是一種連接,表示左邊表的行數乘以右邊表的行數等於笛卡爾積結果集的大小
SELECT * FROM stocks JOIN dividends;
map-side JOIN

所有表中只有一張表是小表,那麼可以在最大的表通過 mapper的時候將小表完全放到內存中。Hive可以在map端執行連接過程(稱爲 map-side JOIN),這是因爲Hive可以和內存中的小表進行逐一匹配,從而省略掉常規連接操作所需要的reduce過程。

-- 設置屬性
-- 也可以將屬性 設置在 $HOME/.hiverc 文件中
set hive.auto.convert.join=true;
set hive.mapjoin.smalltable.filesize=25000000;

-- Hive對右外連接(RIGHT OUTER JOIN) 和全外連接 (FULL OUTER JOIN)不支持這個優化
-- 如果所有表中的數據是分桶的,那麼對於大表,在特定的情況下同樣可以使用這個優化。
-- 分桶優化設置參數
set hive.optimize.bucketmapJOIN=true

-- 如果所涉及的分桶表都具有相同的分桶數,而且數據是按照連接鍵或桶的鍵進行排序的。那麼這時Hive可以執行一個更狂的分類-合併連接(sort-merge JOIN)。
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;

ORDER BY 和 SORT BY

Hive找那個 ORDER BY 語句會對查詢結果集執行一個全局排序。
SORT BY 只會咋每個reducer中對數據進行排序,也就是執行一個局部排序過程。

-- ORDER BY
SELECT s.ymd, s.symbol,s.price_close
FROM stocks s
ORDER BY s.ymd ASC, s.symbol DESC;

-- SORT BY
SELECT s.ymd, s.symbol,s.price_close
FROM stocks s
SORT BY s.ymd ASC, s.symbol DESC;

含有 SORT BY 的 DISTRIBUTE BY

-- DISTRIBUTE BY 控制 map的輸出在reducer中是如何劃分,相同的Key 會分發到同一個 reducer 當中
-- DISTRIBUTE BY 語句要寫在 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;

CLUSTER BY

-- CLUSTER BY 等價於 DISTRIBUTE BY...SORT BY... ASC
SELECT s.ymd, s.symbol, s.price_close 
FROM stocks s
CLUSTER BY s.symbol;

-- 使用 DISTRIBUTE BY...SORT BY 語句或其簡化版的CLUSTER BY 語句會剝奪 SORT BY的並行性,然後這樣可以實現輸出文件的數據是全局排序

類型轉換

--cast()函數,用戶可以使用這個函數對指定的值進行顯式的類型轉換
SELECT name, salary FROM employees
WHERE cast(salary AS FLOAT) <100000.0;

-- 將浮點數轉換成整數的推薦方式是 使用表中列舉的 round() 或者 floor()函數,而不是使用類型轉換操作符 cast

-- BINARY類型只支持 BINARY類型轉換爲STRING類型
-- 用戶同樣可以將STRING 類型轉換爲 BINARY類型
SELECT (2.0*cast(cast(b as string) as double)) from src;

抽樣查詢

--使用rand()函數進行抽樣
SELECT * FROM numbers TABLESAMPLE(BUCKET 3 OUT OF 10 ON rand()) s;
-- 有可能是 2 4 有可能是 7 10 有可能沒有值


-- 按照指定的列而非 rand()函數進行分桶,那麼同一語句多次執行的返回值是相同的
SELECT * FROM numbers TABLESAMPLE(BUCKET 3 OUT OF 10 ON number) s;
-- result 2
SELECT * FROM numbers TABLESAMPLE(BUCKET 5 OUT OF 10 ON number) s;
-- result 4

-- 分桶語句轉給你的分母表示的是數據將會散列的桶的個數,而分子表示將會選擇的桶的個數。


-- 數據塊抽樣
-- Hive提供按照百分比進行抽樣的方式,這種是基於行數的,按照輸入路徑下的數據塊百分比進行的抽樣
SELECT * FROM numbersflat TABLESAMPLE(0.1 PERCENT) s;

-- 這種抽樣方式不一定適用於所有的文件格式。另外,這種抽樣的最小抽樣單元是一個 HDFS數據塊。因此,如果表的數據大小小於普通的塊大小128MB的話,那麼將放回所有行

UNION ALL

--UNION ALL 可以將2個或多個表進行合併
SELECT log.ymd, log.level, log.message
    FROM(
        SELECT 11.ymd, 11.level, 11.message, 'Log1' AS source
        FROM log1 11
    UNION ALL
        SELECT 12.ymd, 12.level, 12.message, 'Log2' AS source
        FROM log1 12
    ) log
SORT BY log.ymd ASC;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章