為什么要有Hive?
在使用Hadoop的過程中,大家都會感覺每次都要寫MR程序才能操作到HDFS的文件,太麻煩了,而且如果項目又趕,項目人員不會寫MR程序,還要花費大量的時間去學,但是我是知道文件內容,是用什么分割的,分割后的每一列是什么意思,感覺好像關系型數據庫。
于是有群人就有了個想法,既然我知道了這些數據分割后的每一列數據的意義,那么能不能把關系型數據庫的SQL解析器搬過來呢?
并把這個解析的映射改為MR程序的映射,用戶只要按照定義好的語法去寫,我就給你解析成對應的MR程序去運行。
什么是Hive?
????? Hive是基于Hadoop的數據倉庫工具,將結構化的數據映射成一張數據庫表,并提供類似SQL查詢功能,稱為HQL,本質就是封裝MR程序。
數據庫和數據倉庫區別(概念)
假設商店場景,數據庫是存儲小物品,而且還是歸類好的物品,并且是庫存不夠的時候就可以很快的就拿到了。
數據倉庫是存儲了一堆的東西,包括已經過期,準備回收的商品,而且很大,并且還可以存儲和數據庫存儲的東西,所相關的東西,比如牛奶賣出去了,這個大的牛奶盒子這些。
數據庫就是存儲存儲定向的數據,如商品的最新信息,畢竟商品的價格每天都會變。
數據倉庫存儲類似歷史數據或主題數據,如,訂單相關的物流信息,商品的歷史價格這些,而且和業務系統不一定完全一樣,主要用于統計、數據分析等
元數據是什么?
????? 元數據就是一個東西的描述信息,比如衣柜,衣柜的外觀、大小、材質、容量、衣柜的哪一格存放了什么東西等等,這些就是元數據。
特點
????? 可擴展性:Hive可以自由的擴展集群規模,一般情況下不需要重啟服務。
????? 延展性:支持用戶自定義函數。
????? 容錯性:節點出問題了,HQL依然可以完成。
組成
用戶接口
CLI:shell命令行
JDBC/ODBC:Hive的Java實現
WebGUI:瀏覽器訪問
元數據存儲
Hive將元數據存儲在數據庫中,Hive中的元數據包括表的名稱、列、分區、屬性、是否是外部表、所在目錄等等
解析
????? 解析器、編譯器、優化器完成HQL查詢語句到詞法解析、語法解析,編譯、優化、查詢計劃生成,查詢計劃是存儲在HDFS,之后調用MR執行。
Hive與傳統數據庫對比
?Hive傳統數據庫
查詢語言HQLSQL
數據存儲HDFSRaw Device or LocalFS
執行MRExecutor
執行延遲高低
數據量多少
索引0.8版本(位圖索引)復雜
Hive數據存儲
DB(數據庫):HDFS下的/user/hive/warehouse文件夾
????? Table(內部表):HDFS下/user/hive/warehouse/數據庫/表,表刪除后對應的文件夾也刪除
????? External Table(外部表):類似Table,就是數據存放位置可以任意指定路徑,刪除后,位于HDFS中的文件不會給刪除。
????? Partition(分區):HDFS下/user/hive/warehouse/數據庫/表/區。
?????????????????????????????????? 分區是一種邏輯性和物理上的優化,以空間換取時間,把一個表的數據切分成兩個進行存儲,這個切分可能是按照時間做切割,后面再查詢的時候,內部會根據條件去判斷要到哪個文件夾去找數據。
????? Bucket:在HDFS中同一個表目錄下根據Hash散列后的不同文件,類似10%2=0,存儲到文件1,=1存儲到文件2,=2存儲到文件3…
使用
bin/hive:本地客戶端
??????????? bin/hive -e "select * from庫名.表名;":執行執行
????? ????? bin/hive-e "use庫名;select * from表名;":直接執行
????? ????? bin/hive-f文件.hql:將復雜的hql語句放到文件內,并執行
?
????? bin/hiveserver2:開啟遠程服務
??????????? 其他機器啟動:bin/beeline
??????????? 其他機器連接:!connectjdbc:hive2://hadoop-s01.levi.com:10000
????? cat ./hivehistory:使用過的歷史HQL命令
配置文件常用項(hive-site.xml)
?javax.jdo.option.ConnectionURL
?jdbc:mysql://localhost:3306/metastore?createDatabaseIfNotExist=true
?javax.jdo.option.ConnectionDriverName
?com.mysql.jdbc.Driver
?javax.jdo.option.ConnectionUserName
?root
?javax.jdo.option.ConnectionPassword
?root
? hive.cli.print.header
?true
?hive.cli.print.current.db
?true
<!-- 簡單的查詢不走mapreduce -->
?hive.fetch.task.conversion
?more
?hive.server2.thrift.port
?10000
?hive.server2.thrift.bind.host
?localhost
? hive.server2.long.polling.timeout
?5000
Hive函數
數據類型
數值
類型支持范圍
TINYINT1字節帶符號整數,從-128到127
SMALLINT2字節帶符號整數,從-32,768到32,767
INT/INTEGER4字節帶符號整數,從-2,147,483,648到2,147,483,647
BIGINT8字節帶符號整數,從-9,223,372,036,854,775,808到9,223,372,036,854,775,807
FLOAT4字節單精度浮點數
DOUBLE8字節雙精度浮點數
DOUBLE精度
DECIMAL十進制數據類型在Hive
? 0.11.0 (Hive -2693)中引入,在Hive 0.13.0 (Hive -3976)中進行了修改。
日期
類型支持版本
TIMESTAMP注意:只能從Hive 0.8.0開始使用
DATE注意:只能從Hive 0.12.0開始使用
INTERVAL注意:只能從Hive 1.2.0開始使用
其他
類型支持版本
arraysARRAY(data_type)注:Hive0.14允許負值和非常量表達式。
mapsMAP(primitive_type,? data_type)注:Hive0.14允許負值和非常量表達式。
structsSTRUCTcol_name? : data_type [COMMENT col_comment], …)
unionUNIONTYPE(data_type,? data_type, …)注意:只能從Hive
? 0.7.0開始使用。
string字符串?
?
ARRAY:ARRAY類型是由一系列相同數據類型的元素組成,這些元素可以通過下標來訪問。比如有一個ARRAY類型的變量fruits,它是由['apple','orange','mango']組成,那么我們可以通過fruits[1]來訪問元素orange,因為ARRAY類型的下標是從0開始的
[if !supportLineBreakNewLine]
[endif]
MAP:MAP包含key->value鍵值對,可以通過key來訪問元素。比如”userlist”是一個map類型,其中username是key,password是value;那么我們可以通過userlist['username']來得到這個用戶對應的password;
[if !supportLineBreakNewLine]
[endif]
STRUCT:STRUCT可以包含不同數據類型的元素。這些元素可以通過”點語法”的方式來得到所需要的元素,比如user是一個STRUCT類型,那么可以通過user.address得到這個用戶的地址。
[if !supportLineBreakNewLine]
[endif]
UNION:UNIONTYPE,他是從Hive 0.7.0開始支持的。
常用HQL
創建數據庫:CREATE DATABASE IF NOT EXISTS levi;
?????
????? 設置變量臨時生效:set hive.cli.print.header=false
?????
創建表:create table if not exists test(idstring,name string,sex string) row format delimited fields terminated by '\t';
????? 創建表:create table newtb as select * fromdb.tname
????? 創建表:create table newtb like db.tname
????? 創建外部表:create external table test2(id int,namestring) row format delimited fields terminated by '\t'
????? 創建表(分區):create table if not exists levi.t_partition(id string,
name string)partitioned by (datestring,hour string)
row format delimited fields terminated by'\t';
????? 創建表(分桶):create table people(id string,name string)clusteredby(id) sorted by (id) into 3 buckets row format?delimited fields terminated by '\t';
????? 創建表(正則):
create table IF NOT EXISTS test (
id string,
name string
)
ROW FORMAT SERDE'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "(\"[^ ]*\")(\"-|[^ ]*\") (\"[^\]]*\") (\"[^\"]*\")(\"[0-9]*\") (\"[0-9]*\") (-|[^ ]*) (\"[^ ]*\")(\"[^\"]*\") (-|[^ ]*) (\"[^ ]*\")"
)
STORED AS TEXTFILE;
????? 查看表信息:desc formatted tbname
????? 導入數據(本地):load data local inpath '/local_path/file' into table 表名;
????? 導入數據(本地)(覆蓋):load data local inpath '/local_path/file'
overwrite into table 表名;
????? 導入數據(HDFS):load
data inpath '/local_path/file' into table 表名;
????? 導入數據:insert into table 表名select * from tbname;
????? 導入數據:insert overwrite into table 表名select * from tbname;
????? 導入數據(分區):load data local inpath'/opt/module/hive-hql/1999092919' into table levi.t_partitionpartition(date='19990929',hour='19');
????? 導出(本地):insert overwrite local directory"/opt/module/hive-hql/data_dir/"row format delimited fieldsterminated by '\t' select * from levi.tname;
????? 導出(HDFS):insertoverwrite directory "path/" select * from levi.tbname;
????? 自定義UDF函數:
public?class?ToLowerCase?extends?UDF {
?public?Text evaluate(Text str) {
?if(null?== str) {
?return?null;
????????? }
?if(null?!= str && str.toString().length() <= 0) {
?return?null;
????????? }
?return?new?Text(str.toString().toLowerCase());
???? }
}
????? 添加到hive的classpath:add jar /opt/lowercase.jar????
????? 添加到Hive函數列表:create
temporary function 函數名as
'包名.類名'
????? 運行函數:select 函數名(name) from student;
排序
????? order by:全局排序,會強行的把reducer改為一個,就算分桶了,還是查詢所有數據。
????? sort by:數據進入reducer前完成排序,因此使用sort by排序,并設置mapred.reduce.tasks>1,則sort by保證每個reducer輸出有序,不保證全局有序,就算是對每一個reduce內部數據進行排序。
????? distribute by:根據ditribute by指定的字段,將數據分發不同reducer,而且分發算法是hash散列算法。
????? cluster by:就是sort by + distribute by。