Hive環境搭建與入門(轉)


作為JAVA的初學者折騰了很久,試了代理服務器等方法,最終發現了這片文章,樓主總結的很不錯!

一、概述
hive是一個基於hadoop的數據倉庫基礎設施, 提供數據的提取轉換加載和查詢, 不適於少數據量(比如幾億)的數據查詢, 也不適於實時或者在線數據的查詢, 是一個非實時的, 離線的數據查詢工具. hive沒有自己的文件格式, 只需要普通的文件格式或者用戶自定義的格式就可以了.

二、環境搭建

hive不需要神馬集群配置, 只是需要編譯一個環境就好了, 編譯的過程, 國人表示很蛋疼, 因為他的ant腳本中, 使用的鏡像居然是facebook的, 翻牆了都沒用表示很糾結. 所以需要把facebook的鏡像改為可用的(最好是國內的, 諸如 人人網, 北京交通大學等等鏡像), 鏡像的選擇可以根據個人喜好和地理位置自由選取, 當然是不能被GFW牆了的.(參考http://www.apache.org/dyn/closer.cgi/hadoop/core/)
1. 下載源代碼: svn co http://svn.apache.org/repos/asf/hive/trunk hive

2. 安裝ant, 過程簡單, 略去 (只要解壓就行了)
3. 修改 hive/build.properties 文件, 將
a). hadoop.mirror的值修改為人人網鏡像 : hadoop.mirror=http://labs.renren.com/apache-mirror
b). hadoop.security.url的值修改為可用的地址, 在網上找了個: hadoop.security.url=http://people.apache.org/~todd/snapshot-for-hive-build/hadoop-0.20.3-CDH3-SNAPSHOT.tar.gz
(這個東東不是一般的鏡像能有的,囧)
c). 將hadoop的版本修改為0.20.2, (貌似0.20.0的地址都不可用了, 難道有大bug?): hadoop.version=0.20.2
4. 修改hive/shims/ 下的ivy.xml 和 build.xml
將對應的hadoop的版本修改為 0.20.2
a) ivy.xml

?
1
 

b) build.xml
(line 61)

?
1
< param name = "hadoop.version.ant-internal" value = "0.20.2" />

5. 編譯
進入源代碼的根目錄hive, 敲下命令: $ant_home/bin/ant package
等待完成… (下載時間可能會有點久, 給點耐心吧).
6. 啟動hive, 只需要啟動前將 $HADOOP_HOME設置為hadoop的安裝目錄即可.

 

三、用法和例子

1, 創建表

?
1
2
3
4
5
6
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;

partitioned by 是創建分區(什么是分區?下邊說明)
沒有指定字段分隔符的話, 默認是使用^A(ctrl-A)為字段分隔符, 換行為記錄分隔符. 指定分隔符用ROW FORMAT row_format 語句

分區: partitioned by , 其實就是在數據的目錄下, 用不同目錄來區分, 比如, dt, 就是按日期(date)來區分, country 國家, hour 小時等等.對應的會在數據的目錄下有分區目錄. 可以建雙分區, 就是子目錄下再分區(其實就是一棵目錄樹).

參考: http://blog.csdn.net/dajuezhao/archive/2010/07/21/5753055.aspx

高級用法:

?
1
2
3
4
5
6
7
8
9
10
11
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;

clustered by 是按照某個字段來進行hash集群

2. 查看表和表結構

?
1
SHOW TABLES;

列出數據倉庫中的所有表

?
1
SHOW TABLES 'page.*' ;

列出所有以”page”為前綴的表, ‘page.*’ 用法和java正則表達式相同

?
1
SHOW PARTITIONS page_view;

列出指定表的所有分區, 如果這個表沒有分區, 則顯示錯誤

?
1
DESCRIBE page_view;

與普通DBMS的desc一樣, 列出指定表的所有字段和字段類型.

?
1
DESCRIBE EXTENDED page_view;

列出指定表的所有字段和字段類型, 以及其他所有屬性.一般用於調試(顯示的格式不友好)

?
1
DESCRIBE EXTENDED page_view PARTITION (ds= '2008-08-08' );

列出指定表指定分區的搜有字段和字段類型, 以及其他所有屬性.(一般也是用於調試)

3. 裝載數據
裝載數據有很多方法:
a. 通過創建一個擴展表, 並指定其location, 然后通過hadoop 的 dfs -put命令將數據放到location指定的位置即可.

?
1
2
3
4
5
6
7
8
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_2008-06-08.txt /user/data/staging/page_view

b. 使用load語句
可以load 本地文件和hdfs文件

?
1
LOAD DATA LOCAL INPATH `/tmp/pv_2008-06-08_us.txt` INTO TABLE page_view PARTITION( date = '2008-06-08' , country= 'US' )

加載本地文件到指定的表中, 還可以指定表的分區.

?
1
LOAD DATA INPATH '/user/data/pv_2008-06-08_us.txt' INTO TABLE page_view PARTITION( date = '2008-06-08' , country= 'US' )

加載hdfs文件到指定的表中, 還可以指定表的分區.

這里的inpath 后便的參數, 可以普通文件路徑(單文件), 也可以是一個目錄的路徑(該目錄下的文件都會被加載, 但要求該目錄下沒有子目錄), 也可以是通配符(如 page_view*.txt, 但通配符匹配的也只是普通文件, 不匹配目錄)

4. 簡單查詢

?
1
2
3
4
INSERT OVERWRITE TABLE user_active
SELECT user .*
FROM user
WHERE user .active = 1;

與SQL不同的是, 我們將查詢結果插入到一個表中, 后續會講到如何查看這個結果表的數據, 或者如何dump到本地文件中.
如果是在hive的control端 hive cli中查詢並查看數據, 就不需要插入到某個表中了, 可以直接查看, 如:

?
1
2
3
SELECT user .*
FROM user
WHERE user .active = 1;

5. 基於分區的查詢
似乎只能通過where語句來解決

?
1
2
3
4
5
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' ;

這里之所以可以這么寫, 是因為在定義table的時候, 使用partitioned by 語句指定了分區, 並且分區字段名為 date, 諸如:PARTITIONED BY(date DATETIME, country STRING) , 如果你的名字不叫date, 別指望date能為你做你想要的事.

6. join
這個類似於SQL, 配合關鍵字on使用

?
1
2
3
4
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 join, right outer join 和 full outer join 等關鍵字來查詢, 例如:

?
1
2
3
4
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' ;

為了在join時檢查一個key在另一個表中的存在性, 可以使用 LEFT SEMI JOIN 關鍵字來查詢, 例如:

?
1
2
3
4
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' ;

另外, 像SQL一樣, 一次查詢可以有多個連接的, 一直join下去都沒問題.

7. 聚集函數

?
1
2
3
4
INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count ( DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;

跟SQL類似, 使用distinct關鍵字可以防止重復計算, 但是在同時使用多個聚集函數時, distinct關鍵字指定的字段必須一致!

8. 多表/文件 插入
insert語句可以插入到hive的表中, 也可以插入到hadoop的hdfs中, 例如

?
1
2
3
4
5
6
7
8
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;

9. 動態分區插入(hive 0.6.0)
沒有使用動態分區插入的情況下:

?
1
2
3
4
5
6
7
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' ;

如果想要將計算的分類結果分別保存到不同類別的分區中, 按照上面的寫法, 必須有多少分區插入多少次, 這樣的寫法是不方便的, 而且多個insert操作對應多個map reduce job, 這樣對系統的性能也有影響. 在hive的0.6.0以上版本中, 增加了動態分區插入的特性, 在計算過程中, hive會自動識別當前字段屬於哪個分區的, 然后插入的時候會插入到對應的分區中(如果該分區還沒創建, 那hive會自動創建這個分區的).
使用動態分區插入之后, 只需要一個insert操作, 也就是只對應一個map reduce job

?
1
2
3
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

這里再partition定義中, 不指定值, select語句中也少了where語句的判斷.
在partition中, country字段沒有指定值, 說明這是一個動態的分區字段, 但dt就有一個值, 說明這是靜態分區字段. 而且在where語句中不需要增加dt的判斷, 因為在partition中已經指定了.目前hive只允動態分區字段出現在partition語句中的最后面(可以多個), 因為分區字段的先后順序表明了他們之間的層級關系.Note that the dynamic partition values are selected by ordering, not name, and taken as the last columns from the select clause.

insert語句中幾個語義上要注意的地方
a.如果查詢結果對應的分區原來存在的話, 將被覆蓋, 如果原來存在的分區, 但是查詢結果中沒有屬於這個分區的, 將不被覆蓋.
b.partition語句中的值最終對應的是hdfs上的path, 所以必須這些值必須滿足path的命名規范, 否則將被urlencode.
c.如果輸入的字段不是string類型, 將會被強制先裝換為string類型.
d.如果輸入的字段值是NULL或者空(empty),記錄將會被放到一個特殊的分區, 這個分區在hive的配置參數中可以得到.
e.動態分區插入的時候可能會在短時間內創建大量的分區, 如果需要自己控制, 可以配置hive.exec.max.dynamic.partitions和 hive.exec.max.dynamic.partitions.pernode這兩個參數, 前者是配置動態分區時最多產生的分區數, 后者是在每個M/R job中產生的最多的分區數, 但計算過程中超過這些數時, 將會產生致命性的錯誤, 並停止job的運行.
f.在動態分區插入中, 有一種情況是搜索的partition參數都是動態的, 這樣是沒有意義的, 所以hive中提供了一個參數來限制這種事的發 生:hive.exec.dynamic.partition.mode=strict/nonstrict 默認值strict就是要求至少有一個是靜態的分區字段.另外還有一個參數來配置是否支持動態分區插入 hive.exec.dynamic.partition=true/false , 默認是關閉的(false)
g.目前, 如果hive開啟了hive.merge.mapfiles=true 或者 hive.merge.mapredfiles=true 會導致不支持動態分區插入, 因為開啟了其中一個在job執行的時候就會把文件合並為一個, 這樣不利於我們的分區, 因為分區其實也是對應到hadoop的hdfs上的.

10. 插入到本地文件

?
1
2
3
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/pv_gender_sum'
SELECT pv_gender_sum.*
FROM pv_gender_sum;

11. 抽樣
抽樣語句允許用戶抽取樣品數據而不是整個表的數據來進行查詢, 抽樣語句只適用於在表創建時使用bucketed on 語句進行分桶的表, 例如:

?
1
2
3
INSERT OVERWRITE TABLE pv_gender_sum_sample
SELECT pv_gender_sum.*
FROM pv_gender_sum TABLESAMPLE(BUCKET 3 OUT OF 32);

抽取總共32桶中的第三桶
抽樣語句的語法如下:
TABLESAMPLE(BUCKET x OUT OF y)
其中, x必須比y小, y必須是在創建表的時候bucket on的數量的因子或者倍數, hive會根據y的大小來決定抽樣多少, 比如原本分了32分, 當y=16時, 抽取32/16=2分, 這時TABLESAMPLE(BUCKET 3 OUT OF 16) 就意味着要抽取第3和第16+3=19分的樣品. 如果y=64, 這要抽取 32/64=1/2份數據, 這時TABLESAMPLE(BUCKET 3 OUT OF 64) 意味着抽取第3份數據的一半來進行.

12. Union all
類似於SQL

?
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);

13. 數組操作.
但一個字段的數據類型時數組時, 可以通過數組的索引來訪問該字段的某個索引值.

?
1
2
SELECT pv.friends[2]
FROM page_views pv;

另外還提供了一個函數 size, 可以求出數組的大小

?
1
2
SELECT pv.userid, size (pv.friends)
FROM page_view pv;

14. Map(關聯性數組)操作
map的訪問類似於 php中對數組的訪問, 直接用key作為索引來訪問數組即可.

?
1
2
3
INSERT OVERWRITE page_views_map
SELECT pv.userid, pv.properties[ 'page type' ]
FROM page_views pv;

與數組類似, 也提供了一個求大小的函數 size

?
1
2
SELECT size (pv.properties)
FROM page_view pv;

15. 自定義map/reduce腳本 & cogroups, 太高級了, 還沒看懂, 先晾着.

16. 變更表(altering table)
a, ALTER TABLE old_table_name RENAME TO new_table_name; 表重命名
b, ALTER TABLE old_table_name REPLACE COLUMNS (col1 TYPE, …); 字段重命名
c, ALTER TABLE tab1 ADD COLUMNS (c1 INT COMMENT ‘a new int column’, c2 STRING DEFAULT ‘def val’); 增加新的字段.

16. 刪除表和分區(drop)
a, DROP TABLE pv_users; 刪除表
b, ALTER TABLE pv_users DROP PARTITION (ds=’2008-08-08′)刪除分區
操作不可恢復

以上手冊本人參考和翻譯自 http://wiki.apache.org/hadoop/Hive/Tutorial

轉自http://www.jiacheo.org/blog/126


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM