Hive 教程(官方Tutorial)

Hive 教程(官方Tutorial)

Tutorial

  • Hive Tutorial
  • Concepts
    • What Is Hive
    • What Hive Is NOT
    • Getting Started
    • Data Units
    • Type System
    • Built In Operators and Function
    • List item
    • Language Capabilities
  • Usage and Examples
    • Creating, Showing, Altering, and Dropping Tables
    • Loading Data
    • Querying and Inserting Data

概念

Hive是什麼

Hive是一個基於Apache Hadoop的數據倉庫。對於數據存儲與處理,Hadoop提供了主要的擴展和容錯能力。

Hive設計的初衷是:對於大量的數據,使得數據彙總,查詢和分析更加簡單。它提供了SQL,允許用戶更加簡單地進行查詢,彙總和數據分析。同時,Hive的SQL給予了用戶多種方式來集成自己的功能,然後做定製化的查詢,例如用戶自定義函數(User Defined Functions,UDFs).

Hive不適合做什麼

Hive不是爲在線事務處理而設計。它最適合用於傳統的數據倉庫任務。

Getting Started

對於Hive, HiveServer2 和Beeline的設置詳情,請參考指南

對於學習Hive,這些書單可能對你有所用處。

以下部分提供了一個關於Hive系統功能的教程。先描述數據類型,表和分區的概念,然後使用例子來描述Hive的功能。

數據單元

根據顆粒度的順序,Hive數據被組織成:
-數據庫:命名空間功能,爲了避免表,視圖,分區,列等等的命名衝突。數據庫也可以用於加強用戶或用戶組的安全。

  • 表:相同數據庫的同類數據單元。例如表page_views,表的每行包含以下列:
    • timestamp -這是一個INT類型,是當頁面被訪問時的UNIX時間戳。
    • userid -這是一個BIGINT類型,用於惟一識別訪問頁面的用戶。
    • page_url -這是一個STRING類型,用於存儲頁面地址。
    • referer_url -這是一個STRING類型,用於存儲用戶是從哪個頁面跳轉到本頁面的地址。
    • IP -這是一個STRING類型,用於存儲頁面請求的IP地址。
  • 分區:每個表可以有一個或多個用於決定數據如何存儲的分區鍵。分區(除存儲單元之外)也允許用戶有效地識別滿足指定條件的行;例如,STRING類型的date_partitionSTRINGcountry_partition。這些分區鍵的每個惟一的值定義了表的一個分區。例如,所有的“2009-12-23”日期的“US”數據是表page_views的一個分區。(注意區分,分區鍵與分區,如果分區鍵有兩個,每個分區鍵有三個不同的值,則共有6個分區)。因此,如果你只在日期爲“2009-12-23”的“US”數據上執行分析,你將只會在表的相關數據上執行查詢,這將有效地加速分析。然而要注意,那僅僅是因爲有個分區叫2009-12-23,並不意味着它包含了所有數據,或者說,這些數據僅僅是那個日期的數據。用戶需要保證分區名字與數據內容之間的關係。分區列是虛擬列,它們不是數據本身的一部分,而是源於數據加載。
  • 桶(Buckets or Clusters):每個分區的數據,基於表的一些列的哈希函數值,又被分割成桶。例如,表page_views可能通過userid分成桶,userid是表page_view的一個列,不同於分區列。這些桶可以被用於有效地抽樣數據。

類型系統

Hive支持原始類型和復要類型,如下所述,查看Hive Data Types

原始類型

  • 類型與表的列相關。支持以下原始類型:
    • Integers(整型)
    • TINYINT -1位的整型
    • SMALLINT -2位的整型
    • INT -4位的整型
    • BIGINT -8位的整型
  • 布爾類型
    • BOOLEAN -TRUE/FALSE
  • 浮點數
    • FLOAT -單精度
    • DOUBLE -雙精度
  • 定點數
    • 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 'IP Address of the User')
 COMMENT 'This is the page view table'
 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_viewuserid列上進行分桶的例子:

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個桶上進行抽樣。合適的排序使得內部操作充分利用熟悉的數據結構來進行更加有效的查詢。

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路徑。用這種方法,用戶可以使用HDFSputcopy命令,複製一個文件到指定的位置,並且附上相應的行格式信息創建一個表指定這個位置。一旦完成,用戶就可以轉換數據和插入他們到任意其他的Hive表中。例如,如果文件/tmp/pv_2016-06-08.txt包含逗號分隔的頁面訪問記錄。這需要以合適的分區加載到表page_view,以下命令可以完成這個目標:

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 querieswriting 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 OUTERFULL 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 的結果與用戶表再連接的查詢:

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 'map_script'
     AS dt, uid
     CLUSTER BY dt) map_output

 INSERT OVERWRITE TABLE pv_users_reduced
     REDUCE map_output.dt, map_output.uid
     USING 'reduce_script'
     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 allcluster by來實現此功能。假設我們想對來自表actions_videoaction_comment的行對uid列進行分組,且需要發送他們到reducer_script定製的reducer,可以使用以下語法:

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

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