Tutorial
Hive Tutorial
Concepts
What Is Hive
What Hive Is NOT
Getting Started
Data Units
Type System
Built In Operators and Functions
Language Capabilities
Usage and Examples
Creating, Showing, Altering, and Dropping Tables
Loading Data
Querying and Inserting Data
概念
Hive是什麼
Hive是一個基於Apache Hadoop的數據倉庫。對於數據存儲與處理,Hadoop提供了主要的擴展和容錯能力。web
Hive設計的初衷是:對於大量的數據,使得數據彙總,查詢和分析更加簡單。它提供了SQL,容許用戶更加簡單地進行查詢,彙總和數據分析。同時,Hive的SQL給予了用戶多種方式來集成本身的功能,而後作定製化的查詢,例如用戶自定義函數(User Defined Functions,UDFs).正則表達式
Hive不適合作什麼
Hive不是爲在線事務處理而設計。它最適合用於傳統的數據倉庫任務。sql
Getting Started
對於Hive, HiveServer2 和Beeline的設置詳情,請參考指南 。數據庫
對於學習Hive,這些書單 可能對你有所用處。apache
如下部分提供了一個關於Hive系統功能的教程。先描述數據類型,表和分區的概念,而後使用例子來描述Hive的功能。數組
數據單元
根據顆粒度的順序,Hive數據被組織成: - 數據庫:命名空間功能,爲了不表,視圖,分區,列等等的命名衝突。數據庫也能夠用於增強用戶或用戶組的安全。安全
表:相同數據庫的同類數據單元。例如表page_views
,表的每行包含如下列:bash
timestamp -這是一個INT
類型,是當頁面被訪問時的UNIX時間戳。
userid -這是一個BIGINT
類型,用於唯一識別訪問頁面的用戶。
page_url -這是一個STRING
類型,用於存儲頁面地址。
referer_url -這是一個STRING
類型,用於存儲用戶是從哪一個頁面跳轉到本頁面的地址。
IP -這是一個STRING
類型,用於存儲頁面請求的IP地址。
分區:每一個表能夠有一個或多個用於決定數據如何存儲的分區鍵。分區(除存儲單元以外)也容許用戶有效地識別知足指定條件的行;例如,STRING
類型的date_partition
和STRING
的country_partition
。這些分區鍵的每一個唯一的值定義了表的一個分區。例如,全部的「2009-12-23」日期的「US」數據是表page_views
的一個分區。(注意區分,分區鍵與分區,若是分區鍵有兩個,每一個分區鍵有三個不一樣的值,則共有6個分區)。所以,若是你只在日期爲「2009-12-23」的「US」數據上執行分析,你將只會在表的相關數據上執行查詢,這將有效地加速分析。然而要注意,那僅僅是由於有個分區叫2009-12-23,並不意味着它包含了全部數據,或者說,這些數據僅僅是那個日期的數據。用戶須要保證分區名字與數據內容之間的關係。分區列是虛擬列,它們不是數據自己的一部分,而是源於數據加載。markdown
桶(Buckets or Clusters):每一個分區的數據,基於表的一些列的哈希函數值,又被分割成桶。例如,表page_views
可能經過userid
分紅桶,userid
是表page_view
的一個列,不一樣於分區列。這些桶能夠被用於有效地抽樣數據。
類型系統
Hive支持原始類型和復要類型,以下所述,查看Hive Data Types
原始類型
類型與表的列相關。支持如下原始類型:
Integers(整型)
TINYINT -1位的整型
SMALLINT -2位的整型
INT -4位的整型
BIGINT -8位的整型
布爾類型
浮點數
定點數 -DECIMAL -用戶能夠指定範圍和小數點位數
字符串 -STRING -在特定的字符集中的一個字符串序列 -VARCHAR -在特定的字符集中的一個有最大長度限制的字符串序列 -CHAR -在特定的字符集中的一個指定長度的字符串序列
日期和時間 -TIMESTAMP -一個特定的時間點,精確到納秒。 -DATE -一個日期
二進制 -BINARY -一個二進制位序列
複雜類型
複雜類型能夠由原始類型和其餘組合類型構建: - 結構體類型(Stuct): 使用點(.)來訪問類型內部的元素。例如,有一列c
,它是一個結構體類型{a INT; b INT},字段a可使用表達式c.a
來訪問。 - Map(key-value鍵值對):使用['元素名']
來訪問元素。例如,有一個MapM
,包含'group'->gid
的映射,則gid的值可使用M['group']
來訪問。 - 數組:數組中的元素是相同的類型。可使用[n]
來訪問數組元素,n
是數組下標,以0開始。例若有一個數組A,有元素['a','b','c']
,則A[1]
返回'b'
。
內置運算符和函數
Hive全部關鍵詞的大小寫都不敏感,包括Hive運算符和函數的名字。
內置運算
內置函數
Hive支持如下內置函數
Hive支持如下內置聚合函數
語言能力
Hive’s SQL提供了基本的SQL操做。這些操做工做於表或分區上。這些操做是: - 可使用WHERE
從表中篩選行 - 可使用SELECT
從表中查詢指定的列 - 兩個表之間能夠join - 能夠在多個group by
的列上使用聚合 - 能夠存儲查詢結構到另外一個表 - 能夠下載表的內容到本地目錄 - 能夠存儲查詢結果到hadoop的分佈式文件系統目錄上 - 能夠管理表和分區(建立,刪除和修改) - 可使用自定義的腳本,來定製map/reduce做業
使用和實例
如下的例子有一些不是最新的,更多最新的信息,能夠參考LanguageManual 。
如下的例子強調了Hive系統的顯著特徵。詳細的查詢測試用例和相應的查詢結果能夠在Hive Query Test Cases’ 上找到。
建立,顯示,修改,和刪除表
加載數據
查詢和插入數據
建立,顯示,修改,和刪除表
建立表
如下例子建立表page_view
:
CREATE TABLE page_view(viewTime INT, userid BIGINT,
page_url
STRING , referrer_url
STRING ,
ip
STRING COMMENT
COMMENT
PARTITIONED
BY (dt
STRING , country
STRING )
STORED
AS SEQUENCEFILE;
在這個例子中,表的列被指定相應的類型。備註(Comments)能夠基於列級別,也能夠是表級別。另外,使用PARTITIONED
關鍵詞定義的分區列與數據列是不一樣的,分區列實際上不存儲數據。當使用這種方式建立表的時候,咱們假設數據文件的內容,字段之間以ASCII 001(ctrl-A)分隔,行之間以換行分隔。
若是數據不是以上述格式組織的,咱們也能夠指定分隔符,以下:
CREATE TABLE page_view(viewTime INT , userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User' ) COMMENT 'This is the page view table' PARTITIONED BY (dt STRING, country STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' STORED AS SEQUENCEFILE;
目前,行分隔符不能指定,由於它不是由Hive決定,而是由Hadoop分隔符。
對錶的指定列進行分桶,是一個好的方法,它能夠有效地對數據集進行抽樣查詢。若是沒有分桶,則會進行隨機抽樣,因爲在查詢的時候,須要掃描全部數據,所以,效率不高。如下例子描述了,在表page_view
的userid
列上進行分桶的例子:
CREATE TABLE page_view(viewTime INT , userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User' ) COMMENT 'This is the page view table' PARTITIONED BY (dt STRING, country STRING) CLUSTERED BY (userid) SORTED BY (viewTime) INTO 32 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' COLLECTION ITEMS TERMINATED BY '2' MAP KEYS TERMINATED BY '3' STORED AS SEQUENCEFILE;
以上例子,經過一個userid
的哈希函數,表被分紅32個桶。在每一個桶中的數據,是以viewTime
升序進行存儲。這樣組織數據容許用戶有效地在這n個桶上進行抽樣。合適的排序使得內部操做充分利用熟悉的數據結構來進行更加有效的查詢。
1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE page_view(viewTime INT, userid BIGINT,
page_url
STRING , referrer_url
STRING ,
friends
ARRAY < BIGINT
> , properties
MAP < STRING ,
STRING > ,
ip
STRING COMMENT
'IP Address of the User' )
COMMENT
'This is the page view table'
PARTITIONED
BY (dt
STRING , country
STRING )
CLUSTERED
BY (userid) SORTED
BY (viewTime)
INTO 32 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED
BY '1'
COLLECTION ITEMS TERMINATED
BY '2'
MAP KEYS TERMINATED
BY '3'
STORED AS SEQUENCEFILE;
在這個例子,CLUSTERED BY
指定列進行分桶,以及建立多少個桶。行格式分隔符指定在hive表中,行如何存儲。在這種分隔符狀況下,指定了字段是如何結束,集合項(數組和map)如何結束,以及map的key是如何結束的。STORED AS SEQUENCEFILE
表示這個數據是以二進制格式進行存儲數據在hdfs上。對於以上例子的ROW FORMAT
的值和STORED AS
表示系統默認值。
表名和列名不區分大小寫。
瀏覽表和分區
SHOW TABLES;
列出數據庫裏的全部的表,也能夠這麼瀏覽:
SHOW TABLES 'page.*' ;
這樣將會列出以page
開頭的表,模式遵循Java正則表達式語法。
SHOW PARTITIONS page_view;
列出表的分區。若是表沒有分區,則拋出錯誤。
DESCRIBE page_view;
列出表的列和列的類型。
DESCRIBE EXTENDED page_view;
列出表的列和表的其餘屬性。這會打印不少信息,且輸出的風格不是很友好,一般用於調試。
DESCRIBE EXTENDED page_view PARTITION (ds=
'2016-08-08' );
列出列和分區的全部屬性。這也會打印出許多信息,一般也是用於調試。
修改表
對已有的表進行重命名。若是表的新名字存在,則報錯:
ALTER TABLE old_table_name RENAME TO new_table_name;
對已有表的列名進行重命名。要確保使用相同的列類型,且要包含對每一個已存在列的一個入口(也就是說,就算不修改其餘列的列名,也要把此列另上,不然,此列會丟失)。
ALTER TABLE old_table_name REPLACE COLUMNS (col1 TYPE,
... );
對已有表增長列:
ALTER TABLE tab1 ADD COLUMNS (c1 INT COMMENT 'a new int column' , c2 STRING DEFAULT 'def val' );
注意: 模式的改變(例如增長列),保留了表的老分區,以避免它是一個分區表。全部對這些列或老分區的查詢都會隱式地返回一個null
值或這些列指定的默認值。
刪除表和分區
刪除表是至關,表的刪除會刪除已經創建在表上的任意索引。相關命令是:
DROP TABLE pv_users;
要刪除分區。修改表刪除分區:
ALTER TABLE pv_users DROP PARTITION (ds='2016-08-08' )
注意:此表或分區的任意數據都將被刪除,並且可能沒法恢復。
加載數據
要加載數據到Hive表有許多種方式。用戶能夠建立一個「外部表」來指向一個特定的HDFS路徑。用這種方法,用戶可使用HDFSput
或copy
命令,複製一個文件到指定的位置,而且附上相應的行格式信息建立一個表指定這個位置。一旦完成,用戶就能夠轉換數據和插入他們到任意其餘的Hive表中。例如,若是文件/tmp/pv_2016-06-08.txt
包含逗號分隔的頁面訪問記錄。這須要以合適的分區加載到表page_view
,如下命令能夠完成這個目標:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE EXTERNAL TABLE page_view_stg(viewTime INT , userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User' , country STRING COMMENT 'country of origination' ) COMMENT 'This is the staging page view table' ROW FORMAT DELIMITED FIELDS TERMINATED BY '44' LINES TERMINATED BY '12' STORED AS TEXTFILE LOCATION '/user/data/staging/page_view' ;
hadoop dfs -put /tmp/pv_2016-06-08.txt /user/data/staging/page_view
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2016-06-08' , country='US' ) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null , null , pvs.ip WHERE pvs.country = 'US' ;
其中,‘44’是逗號的ASCII碼,‘12’是換頁符(NP from feed,new page)。null
是做爲目標表中的數組和map類型插入,若是指定了合適的行格式,這些值也能夠來自外部表。
若是在HDFS上有一些歷史數據,用戶想增長一些元數據,以便於可使用Hive來查詢和操縱這些數據,這個方法是頗有用的。
另外,系統也支持直接從本地文件系統上加載數據到Hive表。表的格式與輸入文件的格式須要相同。若是文件/tmp/pv_2016-06-08
包含了US
數據,而後咱們不須要像前面例子那樣的任何篩選,這種狀況的加載可使用如下語法完成:
LOAD DATA LOCAL INPATH /tmp/pv_2016-06 -08 _us.txt INTO TABLE page_view PARTITION(date ='2016-06-08' , country='US' )
路徑參數能夠是一個目錄(這種狀況下,目錄下的全部文件將被加載),一個文件,或一個通配符(這種狀況下,全部匹配的文件會上傳)。若是參數是目錄,它不能包含子目錄。一樣,通配符只匹配文件名。
在輸入文件/tmp/pv_2016-06-08.txt
很是大的狀況下,用戶能夠採用並行加載數據的方式(使用Hive的外部工具)。只要文件在HDFS上-如下語法能夠用於加載數據到Hive表:
LOAD DATA INPATH '/user/data/pv_2016-06-08_us.txt' INTO TABLE page_view PARTITION(date ='2016-06-08' , country='US' )
對於這個例子,咱們假設數組和map在文件中的值爲null
。
更多關於加載數據到表的信息,請參考Hive Data Manipulation Language ,建立外部表的另一個例子請參考External Tables 。
查詢和插入數據
Simple Query
Partition Based Query
Joins
Aggregations
Multi Table/File Inserts
Dynamic-Partition Insert
Inserting into Local Files
Sampling
Union All
Array Operations
Map (Associative Arrays) Operations
Custom Map/Reduce Scripts
Co-Groups
Hive查詢操做在文檔Select ,插入操做在文檔insert data into Hive Tables from queries 和writing data into the filesystem from queries 。
簡單的查詢
對於全部的活躍用戶,可使用如下查詢格式:
INSERT OVERWRITE TABLE user_active SELECT user .* FROM user WHERE user .active = 1 ;
注意:不像SQL,咱們總是插入結果到表中。隨後咱們會描述,用戶如何檢查這些結果,甚至把結果導出到一個本地文件。你也能夠在Beeline 或HiveCLI 執行如下查詢:
SELECT user .* FROM user WHERE user .active = 1 ;
這在內部將會重寫到一些臨時文件,並在Hive客戶端顯示。
基於查詢的分區
在一個查詢中,要使用什麼分區,是由系統根據where
在分區列上條件自動的決定。例如,爲了獲取全部2008年3月份,從域名xyz.com
過來的page_views,能夠這麼寫查詢:
INSERT OVERWRITE TABLE xyz_com_page_views SELECT page_views.* FROM page_views WHERE page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31' AND page_views.referrer_url like '%xyz.com' ;
注意:在這裏使用的page_views.date
是用PARTITIONED BY(date DATATIME, country STRING)
定義的.若是你的分區命名不同,那麼不要期望.date
可以作你想作的事情,即沒法得到分區的優點。
鏈接
表的鏈接可使用如下命令:
INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03' ;
想實現外鏈接,用戶可使用LEFT OUTER
,RIGHT OUTER
或FULL OUTER
關鍵詞來指示不一樣的外鏈接(左保留,右保留或兩端都保留)。例如,想對上面的查詢作一個FULL OUTER
,相應的語法能夠像下面這樣:
INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u FULL OUTER JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03' ;
爲了檢查key在另一個表中是否存在,用戶可使用LEFT SEMI JOIN
,正如如下例子同樣:
INSERT OVERWRITE TABLE pv_users SELECT u.* FROM user u LEFT SEMI JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03' ;
爲了鏈接多個表,可使用如下語法:
INSERT OVERWRITE TABLE pv_friends SELECT pv.*, u.gender, u.age, f.friends FROM page_view pv JOIN user u ON (pv.userid = u.id) JOIN friend_list f ON (u.id = f.uid) WHERE pv.date = '2008-03-03' ;
注意:Hive只支持equi-joins 。因此,把最大的表放在join
的最右邊,能夠獲得最好的性能。
聚合
統計用戶每一個性別的人數,可使用如下查詢:
INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count (DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;
能夠同時作多個聚合,然而,兩個聚合函數不能同時用DISTINCT
做用於不一樣的列,如下狀況是能夠的(DISTINCT
做用於相同列):
INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count (DISTINCT pv_users.userid), count (*), sum (DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;
然而,如下狀況(DISTINCT
做用於不一樣的列)是不容許的:
INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count (DISTINCT pv_users.userid), count (DISTINCT pv_users.ip) FROM pv_users GROUP BY pv_users.gender;
多表/文件插入
聚合或簡單查詢的輸出能夠插入到多個表中,或者甚至是HDFS文件(可以使用HDFS工具進行操縱)。例如,若是沿用前面的「性別分類」,例子以下:
FROM pv_users
INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count_distinct(pv_users.userid) GROUP BY pv_users.gender INSERT OVERWRITE DIRECTORY '/user/data/tmp/pv_age_sum' SELECT pv_users.age, count_distinct(pv_users.userid) GROUP BY pv_users.age;
第一個插入語句將結果插入到Hive表中,而第二個插入語句是將結果寫到HDFS文件。
動太分區插入
在前面的例子中,咱們知道,在插入語句中,只能有一個分區。若是咱們想加載到多個分區,咱們必須像如下描述來使用多條插入語句:
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08' , country='US' ) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null , null , pvs.ip WHERE pvs.country = 'US' INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08' , country='CA' ) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null , null , pvs.ip WHERE pvs.country = 'CA' INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08' , country='UK' ) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null , null , pvs.ip WHERE pvs.country = 'UK' ;
爲了加載數據到所有的country
分區到指定的日期。咱們必須在輸入數據中爲每一個country
增長一條插入語句。這是很是不方便的,由於咱們須要提早建立且知道已存在哪些country
分區列表。若是哪天這些country
列表變了,咱們必須修改咱們的插入語句,也應該建立相應的分區。這也是很是低效的,由於每一個插入語句可能都是轉換成一個MapReduce做業。
動態分區插入(Dynamic-partition insert)(或multi-partition插入) 就是爲了解決以上問題而設計的,它經過動態地決定在掃描數據的時候,哪些分區應該建立和填充。這個新的特徵是在版本0.6.0加入的。在動態分區插入中,輸入列被評估,這行應該插入到哪一個分區。若是分區沒有建立,它將自動建立這個分區。使用這個特徵,咱們僅僅須要插入語桀犬吠堯 來建立和填充全部須要的分區。另外,由於只有一個插入語句,相應的也只有一個MapReduce做業。相比多個插入語句的狀況,這將顯著地提升性能且下降Hadoop集羣負載。
如下是使用一個插入語句,加載數據到全部country
分區的例子:
FROM page_view_stg pvs
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08' , country) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null , null , pvs.ip, pvs.country
與多條插入語句相比,動態分區插入有一些語法上的不一樣: - country
出如今PARTITION
後面,可是沒有具體的值。這種狀況,country
就是一個動態分區列。另外一方面,dt
有一個值,這意味着它是一個靜態的分區列。若是一個列是動態分區列,它的值將會使用輸入列的值。目前,咱們僅僅容許在分區條件的最後一列放置動態分區列,由於分區列的順序,指示了它的層級次序(意味着dt
是根分區,country
是子分區)。咱們不能這樣指定分區(dt,country=’US’),由於這表示,咱們須要更新全部的日期的分區且它的country
子分區是‘US’。
一個額外的pvs.country
列被加入在查詢語句中。這對動態分區列來講,至關於輸入列。注意:對於靜態分區列,咱們不須要添加一個輸入列,由於在PARTITION語句中,它的值已經知道。注意:動態分區列的值(不是名字)查出來是有序的,且是放在select語句的最後。
動態分區插入的語義: - 對於動態分區列,當已經此分區時,(例如,country='CA'
已存在dt
根分區下面)若是動態分區插入與輸入數據中相同的值(’CA’),它將會被重寫(overwritten)。
插入到本地文件
在某些場合,咱們須要把輸出寫到一個本地文件,以便於能用excel表格 打開。這可使用如下命令:
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/pv_gender_sum' SELECT pv_gender_sum.* FROM pv_gender_sum;
抽樣
抽樣語句容許用戶對數據抽樣查詢,而不是全表查詢。當前,抽樣是對那些在CREATE TABLE
語句的CLUSTERED BY
修飾的列上。如下例子,咱們從表pv_gender_sum
表中的32個桶中,選擇第3個桶。
INSERT OVERWRITE TABLE pv_gender_sum_sample SELECT pv_gender_sum.* FROM pv_gender_sum TABLESAMPLE(BUCKET 3 OUT OF 32 );
一般,TABLESAMPLE
的語法像這樣:
TABLESAMPLE(BUCKET x
OUT OF y)
這個y
必須是桶的數量的因子或倍數,桶的數量是在建立表的時候指定的。抽樣所選的桶由桶大小,y和x共同決定。若是y和桶大小相等,則抽樣所選的桶是x對y的求模結果。
TABLESAMPLE(BUCKET
3 OUT OF 16 )
這將抽樣第3個和第19個桶。桶的編號從0開始。
tablesample
語句的另外一方面:
TABLESAMPLE(BUCKET
3 OUT OF 64 ON userid)
這將抽取第3個桶的一半。
union all
這個語言也支持union all
,若是假設咱們有兩個不一樣的表,分別用來記錄用戶發佈的視頻和用戶發佈的評論,如下例子是一個union all 的結果與用戶表再鏈接的查詢:
1
2
3
4
5
6
7
8
9
10
11
12
13
INSERT OVERWRITE TABLE actions_users SELECT u.id, actions.date FROM ( SELECT av.uid AS uid FROM action_video av WHERE av.date = '2008-06-03' UNION ALL SELECT ac.uid AS uid FROM action_comment ac WHERE ac.date = '2008-06-03' ) actions JOIN users u ON (u.id = actions.uid);
數組操做
表的數組列能夠這樣:
CREATE TABLE array_table (int_array_column ARRAY<INT >);
假設pv.friends 是類型ARRAY<INT>
(也就是一個整型數組),用戶能夠經過索引號獲取數組中特定的元素,以下:
SELECT pv.friends[2 ] FROM page_views pv;
這個查詢獲得的是pv.friends裏的第三個元素。
用戶也可使用函數size
來獲取數組的長度,以下:
SELECT pv.userid, size (pv.friends) FROM page_view pv;
Map(關聯數組)操做
Map提供了相似於關聯數組的集合。這樣的結構不只能夠由程序建立。咱們也將很快能夠繼承這個。假設pv.properties是類型map<String,String>
,以下:
INSERT OVERWRITE page_views_map SELECT pv.userid, pv.properties['page type' ] FROM page_views pv;
這將查詢表page_views
的‘page_type‘屬性。
與數組類似,也可使用函數size
來獲取map的大小:
SELECT size (pv.properties) FROM page_view pv;
定製Map/Reduce腳本
經過使用Hive語言原生支持的特徵,用戶能夠插入他們本身定製的mapper和reducer在數據流中。例如,要運行一個定製的mapper腳本script-map_script
和reducer腳本script-reduce_script
),用戶能夠執行如下命令,使用TRANSFORM
來嵌入mapper和reducer腳本。
注意:在執行用戶腳本以前,表的列會轉換成字符串,且由TAB
分隔,用戶腳本的標準輸出將會被做爲以TAB
分隔的字符串列。用戶腳本能夠輸出調試信息到標準錯誤輸出,這個信息也將顯示hadoop的詳細任務頁面上。
FROM (
FROM pv_users
MAP pv_users.userid, pv_users.
date
USING
AS dt, uid
CLUSTER
BY dt) map_output
INSERT OVERWRITE TABLE pv_users_reduced
REDUCE map_output.dt, map_output.uid
USING
AS date , count;
map腳本樣本(weekday_mapper.py)
import sys
import datetime
for line in sys.
stdin :
line =
line .strip()
userid, unixtime =
line .
split (
'\t' )
weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()
print
',' .join([userid, str(weekday)])
固然,對於那些常見的select轉換,MAP和REDUCE都是「語法糖」。內部查詢也能夠寫成這樣:
SELECT TRANSFORM(pv_users.userid, pv_users.date ) USING 'map_script' AS dt, uid CLUSTER BY dt FROM pv_users;
Co-Groups
在使用map/reduce的羣體中,cogroup
是至關常見的操做,它是未來自多個表的數據發送到一個定製的reducer,使得行由表的指定列的值進行分組。在Hive的查詢語言中,可使用如下方式,經過使用union all
和cluster by
來實現此功能。假設咱們想對來自表actions_video
和action_comment
的行對uid
列進行分組,且須要發送他們到reducer_script
定製的reducer,可使用如下語法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM (
FROM (
FROM action_video av
SELECT av.uid AS uid, av.id AS id, av.date AS date UNION ALL FROM action_comment ac SELECT ac.uid AS uid, ac.id AS id, ac.date AS date ) union_actions SELECT union_actions.uid, union_actions.id, union_actions.date CLUSTER BY union_actions.uid) map INSERT OVERWRITE TABLE actions_reduced SELECT TRANSFORM(map.uid, map.id, map.date ) USING 'reduce_script' AS (uid, id, reduced_val);
翻譯自: https://cwiki.apache.org/confluence/display/Hive/Tutorial