1 Hive簡介
Hadoop項目下包含很多子項目,這些項目很多是圍繞hadoop的處理數據的核心基礎上的。我們可以簡單的看一下
Pig————一種高級數據流語言
Hive————一種類SQL數據倉庫基礎設施
HBase————一種模仿Google Bigtable的分布式的、面向列的數據庫
ZooKeeper————一種用於管理分布式應用之間共享狀態的可靠的協同系統
Chukwa————一種用於管理大型分布式系統的數據收集系統
hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張數據庫表,並提供完整的sql查詢功能,可以將sql語句轉換為MapReduce任務進行運行。 其優點是學習成本低,可以通過類SQL語句快速實現簡單的MapReduce統計,不必開發專門的MapReduce應用,十分適合數據倉庫的統計分析。
Hive是建立在 Hadoop 上的數據倉庫基礎構架。它提供了一系列的工具,可以用來進行數據提取轉化加載(ETL),這是一種可以存儲、查詢和分析存儲在 Hadoop 中的大規模數據的機制。Hive 定義了簡單的類 SQL 查詢語言,稱為 HQL,它允許熟悉 SQL 的用戶查詢數據。同時,這個語言也允許熟悉 MapReduce 開發者的開發自定義的 mapper 和 reducer 來處理內建的 mapper 和 reducer 無法完成的復雜的分析工作。Hive 沒有專門的數據格式。 Hive 可以很好的工作在 Thrift 之上,控制分隔符,也允許用戶指定數據格式。
HiveQL是Hive的類SQL語言,你可以發起一個查詢來實現與Hive的交互。例如從user表獲取所有活躍用戶的查詢
select user.* from user where user.active = 1;
Hive的設計體現出它是一個管理和查詢結構化數據的系統。通過專注結構化數據,Hive可以實現MapReduce一般所不具備的某些優化和可用性功能。它沿用了關系數據庫的常見概念,如果表、行、列和schema,以便於學習。
通常有幾種方法與Hive交互,包括WebGUI和JDBC接口,但是大多數交互傾向利用命令行界面(CLI)。下面是Hive的高層體現結構框圖。

2 試試幾個命令
示例1 查詢的示例
在正式講解HiveQL之前,現在命令行方式下運行幾條命令是有好處的。可以感受HiveQL是如何工作的,也可以自己隨便探索一下。
可以到美國專利局網站下載試驗數據http://www.nber.org/patents/ cite75_99.txt,ASCII CSV格式下的。解壓后是個txt文本文件。在Hive中,先定義存儲該數據的表。
CREATE TABLE cite(citing INT, cited INT) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE;
HiveQL語句以分號結束,如上所述,一條語句可以跨多行,直到分號才結束。上面的命令第一行是創建表及兩個字段,其他行告訴數據的存儲方式是文本文件以及解析方式是以逗號分隔的字段。
hive> CREATE TABLE cite(citing INT, cited INT) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ',' > STORED AS TEXTFILE; OK Time taken: 25.317 seconds
由於本人是用比較老的筆記本上裝的虛擬機,並且是集群方式運行,所以創建表是比較慢的。。。。。見諒— —
示例2 查看所有創建的表
hive> SHOW TABLES; OK cite t_afan_test Time taken: 0.423 seconds
示例3 查看表的結構
hive> describe cite; OK citing int cited int Time taken: 0.405 seconds
示例4 加載數據到表中
hive> LOAD DATA LOCAL INPATH '/usr/local/hive/bin/patentData.txt' OVERWRITE INTO TABLE cite; Copying data from file:/usr/local/hive/bin/patentData.txt Copying file: file:/usr/local/hive/bin/patentData.txt Loading data to table default.cite Deleted hdfs://master:9000/user/hive/warehouse/cite OK Time taken: 0.367 seconds
注意加載的文件路徑。
這告訴Hive從本地文件系統上一個名為patentData.txt的文件中把數據加載到cite表中。在此過程中,本地計算機會把數據上傳到HDFS,放在Hive管理的某些目錄下。
當加載數據時,Hive不會讓任何違反schema的數據進入表中,Hive會將這些數據替換為空值,我們可以使用一個簡單select語句瀏覽cite表中的數據。
hive> select * from cite limit 10; OK NULL NULL 3858241 956203 3858241 1324234 3858241 3398406 3858241 3557384 3858241 3634889 3858242 1515701 3858242 3319261 3858242 3668705 3858242 3707004 Time taken: 0.425 seconds
我們將schema定義為兩列整數,首行是citing和cited兩個值,因此違反了schema,所以變成了空值。
統計表的行數,由於原始的文件70多兆,大概有1600萬行,本人出於本機性能考慮- -,只放了1000多行數據。下面是處理過程
hive> select count(1) from cite; Total MapReduce jobs = 1 Launching Job 1 out of 1 Number of reduce tasks determined at compile time: 1 In order to change the average load for a reducer (in bytes): set hive.exec.reducers.bytes.per.reducer=<number> In order to limit the maximum number of reducers: set hive.exec.reducers.max=<number> In order to set a constant number of reducers: set mapred.reduce.tasks=<number> Starting Job = job_201307140515_0001, Tracking URL = http://master:50030/jobdetails.jsp?jobid=job_201307140515_0001 Kill Command = /usr/local/hadoop/bin/../bin/hadoop job -Dmapred.job.tracker=master:9001 -kill job_201307140515_0001 Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1 2013-07-14 06:45:22,599 Stage-1 map = 0%, reduce = 0% 2013-07-14 06:46:17,100 Stage-1 map = 100%, reduce = 0% 2013-07-14 06:46:42,596 Stage-1 map = 100%, reduce = 100% Ended Job = job_201307140515_0001 MapReduce Jobs Launched: Job 0: Map: 1 Reduce: 1 HDFS Read: 17411 HDFS Write: 5 SUCESS Total MapReduce CPU Time Spent: 0 msec OK 1027 Time taken: 147.815 seconds
雖然是1027行,但是花了將近3分鍾,機器性能不太好。
通過這些消息,可以知道該查詢生成了一個MapReduce作業。Hive之美在於用戶根本不需要知道MapReduce的存在。用戶所需要關心的僅僅是一種類似於SQL的語言查詢數據庫。
上述查詢結果被直接輸出在屏幕上,大多數情況下,查詢結果應該被存盤,而且通常被放在其他的Hive表中。我們下一個查詢會查到每個專利的引用頻率。首先生成一個表來存儲它的結果:
hive> create table cite_count(cited int, count int); OK Time taken: 0.357 seconds
我們可以執行一個查詢來得到引用頻率,這個查詢再次使用與SQL相類似的COUTN和GROUP BY功能,再加上insert overwrite table,就可以讓hive將結果寫入表中。
hive> insert overwrite table cite_count select cited,count(citing) from cite group by cited; Total MapReduce jobs = 1 Launching Job 1 out of 1 Number of reduce tasks not specified. Estimated from input data size: 1 In order to change the average load for a reducer (in bytes): set hive.exec.reducers.bytes.per.reducer=<number> In order to limit the maximum number of reducers: set hive.exec.reducers.max=<number> In order to set a constant number of reducers: set mapred.reduce.tasks=<number> Starting Job = job_201307140515_0002, Tracking URL = http://master:50030/jobdetails.jsp?jobid=job_201307140515_0002 Kill Command = /usr/local/hadoop/bin/../bin/hadoop job -Dmapred.job.tracker=master:9001 -kill job_201307140515_0002 Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1 2013-07-14 06:58:14,823 Stage-1 map = 0%, reduce = 0% 2013-07-14 06:58:22,874 Stage-1 map = 100%, reduce = 0% 2013-07-14 06:58:34,933 Stage-1 map = 100%, reduce = 100% Ended Job = job_201307140515_0002 Loading data to table default.cite_count Deleted hdfs://master:9000/user/hive/warehouse/cite_count Table default.cite_count stats: [num_partitions: 0, num_files: 1, num_rows: 0, total_size: 10188, raw_data_size: 0] 1024 Rows loaded to cite_count MapReduce Jobs Launched: Job 0: Map: 1 Reduce: 1 HDFS Read: 17411 HDFS Write: 10188 SUCESS Total MapReduce CPU Time Spent: 0 msec OK Time taken: 37.106 seconds
查詢執行告訴我們有1024行被裝載到引用頻率表中。我們可以執行HiveQL語句瀏覽這個引用頻率表。
hive> select * from cite_count limit 10; OK NULL 0 14040 1 16749 1 17445 1 34608 1 55828 1 129311 1 170178 1 205960 1 213525 1 Time taken: 0.182 seconds
示例:當你使用完這個表后,可以使用drop table來刪除它。
hive> drop table cite_count; OK Time taken: 2.571 seconds
可以使用exit命令來退出Hive會話
3 深入HiveQL
3.1 數據模型
我們看的Hive將表作為基本的數據模型。物理上,Hive將表以目錄形式放在/user/hive/warehouse下。例如,我們前面生成cite表將放在/user/hive/warehouse/cite目錄下。輸出結果的cite_count表則被放在/user/hive/warehouse/cite_count目錄下。在大多數基本設置中,一個表下面的目錄結構部只有一層,表中的數據分散在一個目錄下的多個文件中。
關系數據庫在列上使用索引來加速對這些列的查詢。Hive則使用了分區列的概念,根據列的值將表划分為多個分區。分區列是一種划分標准的列,有點像關系型數據庫里面的索引。例如,state列將表划分為50個分區,每個州有一個分區。每個州有一個分區。date列是用作日志數據的分區列,每天的數據歸屬於其自己的分區。Hive將分區列與常規的數據列區別看待,在分區列上執行查詢要高效得多。這是因為Hive在物理上將不同的分區存在不同的目錄中。例如,假設你有一個名為users的表,包含data和state兩個分區列(加上常規的數據列)。Hive將這個表生成如下的目錄結構

所有加利福尼亞(state=CA)2009年9月1日(date=20090901)的用戶數據放在一個目錄中,而其他分區的數據放在其他目錄中。如果進來一個查詢,它請求加利福尼亞州在2009年9月1日的用戶數據,Hive僅需處理那個目錄下的數據,而不用管其他分區中存儲的users表中的數據。對分區列的跨區查詢涉及對多個目錄的處理,但是Hive仍能避免去掃描users中的所有數據。某種程度上,分區為Hive帶來的好處類似於所以對傳統關系數據庫的作用。但是分區在粒度上遠遠不及索引。
除了分區,Hive數據模型還應用了通的概念,它可以提供對隨機樣本數據的高效查詢。例如,當計算一個列的平均值時,數據的隨機樣本可以提供一個很好的近似結果。基於對桶列的散列,桶將分區的數據,進一步划分為為特定數目的文件。如果根據users表中的用戶id,我們將桶的個數設定為32,那么Hive中的表將會有如下完整文件結構。
桶列結構

每個分區有32個桶,通過基於用戶id的分桶,Hive會知道part-00000.....part-00031中的每個文件都是一個用戶的隨機樣本。許多匯總統計的計算在樣本數據集上依然有相當好的精度。分桶對於加速一些查詢特別有用。例如Hive的查詢可以用所有分區的part-00000這段數據,它僅為所有數據的1/32.
3.2 表的管理
我們已經看到如何為專利引用數據集生成一個樣本表。現在讓我們剖析一個更為復雜的表生成語句。這次生成一個名為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' partioned by (dt string, country string) clustered by(userid) into 32 buckets row format delimited fields terminated by '\t' lines terminated by '\n' stored as sequencefile;
我們分析這個很長的語句:
create table page_view(viewTime int, userid bigint, page_url string, referrer_url string, ip string comment 'ip address of the user')
它指定了表名及其schema,包含列名和它們的類型。Hive支持如下的數據類型。
tinyint————單字節整數,1個字節 smallint————雙字節整數 int————四字節整數 bigint————八字節整數 double————雙精度浮點數 string————字符序列
注意這里沒有布爾類型,通常用tinyint來替代。Hive還支持復雜的數據類型,如結構、映射和數組,它們可以嵌套。
注釋:
comment 'this is the page view table'
這個是對每一列附加一個描述性注釋。上面是描述ip的
指定分區列:
partioned by(dt string, country string)
前面已經討論過,分區列面向查詢進行了優化,它們不同於數據列viewTime,userid,page_url,referrer_url和ip。對於特定的行,分區列的值並沒有顯式地在行中存儲,它隱含在目錄路徑中。但是,分區列和數據列的查詢在用法上並無差別。
指定分桶的信息
clustered by (userid) into 32 buckets
clustered by(...)into...buckets語句指定了分桶信息,其中包含參與隨機采樣的列,以及生成的桶數。桶數的選擇依賴於以下標准:
1.每個分區下數據的大小
2.打算使用的樣本大小
第一個標准很重要,因為在分區被進一步划分為指定格式的桶之后,你並不想讓每個桶文件太小而導致hadoop的效率很低。另一方面,桶應該和你所用樣本有相同的大小或者比它更小。如果樣本大小為用戶基數的百分之三(1/32)左右,基於用戶將分桶數設為32就是一個很好的選擇。
與分區不同,在數據被寫入表時,Hive不會自動地強制分桶,指定分桶信息僅會告知Hive當數據寫入一個表時,你會手動地強制分桶(取樣)的標准,而Hive可以在處理查詢時利用這一優勢。為了強制設置分桶的標准,你需要在填充表時正確地設置reducer的個數。
ROW FORMAT子句告訴Hive表中數據按行存儲的方式,若無此子句,Hive默認以換行符作為行分隔符,以001(Ctrl+A)的ASCII值作為字段分隔符。我們的子句告訴Hive改為使用制表符字符作為字段分隔符。我們還告訴Hive使用換行符作為行分隔符,但那已經是默認值,我們在這里包括它只是為了演示而已。
row format delimited fields terminated by '\t' lines terminated by '\n'
最終,最后一個子句告訴Hive用於存儲表中數據的文件格式
stored as sequencefile
目前hive支持兩種格式,sequencefile和textfile,序列文件是一種壓縮的格式,通常可提供更高的性能。
我們可以在create table語句中添加一個external修飾符,這樣表被創建為指向一個現有的數據目錄。你需要指定此目錄的位置。
create table page_view(viewTime int, userid bigint, page_url string, referrer_url string, ip string comment 'ip address of the user') location '/path/to/existing/table/in/HDFS';
在生成一個表之后,你可以用describe命令在hive中查詢這個表的schema結構 describe page_view; 修改表的名稱 alter table page_view rename to pv; 增加新的列 alter table page_view add columns(newcol string); 刪除一個分區 alter table page_view drop partion(dt='2009-09-01'); 要刪除整個表 drop table page_view 查看所有的表 show tables 用正則表達式查看部分表 show tables 'page_.*' 裝載數據 load data local inpath 'page_view.txt' overwrite into table page_view partion (dt = '2009-09-01', country='US'); 當操作來自本地系統文件中的數據時,可以執行Hive CLI中的本地UNIX命令。 獲取一個文件的列表 hive>!ls 或檢查文件的前幾行 hive>!head hive_result 請注意!和;周圍的空格不是必要的。主要為了提高可讀性。
執行查詢
大多數情況下HiveQL查詢和SQL查詢驚人地相似,一個通常的差別為HiveQL查詢的結果相對較大。幾乎總有一個insert子句,以便告訴Hive把結果存起來,往往存到其他的表中。
insert overwrite table query_result 也會是HDFS的一個目錄 insert overwrite dictionary '/hdfs_dir/query_result' 有時還會是一個本地目錄 insert overwrite local dictionary '/local_dir/query_result' 也就是: insert overwrite table query_result select * from page_view where country = 'US';
組函數:
注意HiveQL使用count(1)代替SQL的count(*)。
像SQL一樣,group by子句允許在組上執行聚合查詢,此查詢將列出每個國家的頁面瀏覽數量:
select country, count(1) from page_view group by country
而下面的查詢將列出每個國家的唯一用戶數
select country, count(distinct userid) from page_view group by country
3.3 HiveQL的運算符及聚合函數





3.4 聯結查詢
對於用戶而言,尋找Pig Latin和HiveQL這種更高級的語言的一個主要動力在於支持聯結操作。目前HiveQL只支持等聯結。聯結查詢的示例如下:
有兩個表user和page_view
insert overwrite table query_result select pv.*,u.gender,u.age from page_view pv join user u on (pv.userid = u.id);
在語法上,將關鍵字join添加到from子句中兩個表之間,然后在關鍵字on后面指定聯結的列,若言聯結兩個以上的表,重復這種模式
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);
我們可以通過修改from子句為任何查詢添加采樣,該查詢會去計算平均瀏覽時間,除非這個平均值僅取自32桶的一桶數據
select avg(viewTime) from page_view tablesample(bucket 1 out of 32) tablesample的一般語法如下 tablesample(bucket x out of y)
查詢樣本的大小為1/y左右,此外,y為創建時所指定的桶數的倍數或因數。例如,如果我們將y改為16,查詢為
select avg(viewTime) from page_view tablesample(bucket 1 out of 16)
那么樣本的大小為大約為16個用戶取一個,表仍有32個桶,但Hive僅去1到17並一起處理以滿足該查詢。另一方面,如果取y為64,則Hive會對單個桶中的一半數據執行查詢。x的值僅用於選擇要使用的桶,在真正隨機的情況下,它的取值不會產生什么影響。
除了內置的函數外,程序員還可以在Hive中添加UDF來定制處理函數
