hive簡(jiǎn)介
解釋一:Hive是一個(gè)數(shù)據(jù)倉(cāng)庫(kù)基礎(chǔ)工具在Hadoop中用來(lái)處理結(jié)構(gòu)化數(shù)據(jù)皱炉。它架構(gòu)在Hadoop之上,總歸為大數(shù)據(jù),并使得查詢和分析方便另萤。并提供簡(jiǎn)單的sql查詢功能梯影,可以將sql語(yǔ)句轉(zhuǎn)換為MapReduce任務(wù)進(jìn)行運(yùn)行
解釋二:Hive 是建立在 Hadoop 上的數(shù)據(jù)倉(cāng)庫(kù)基礎(chǔ)構(gòu)架巫员。它提供了一系列的工具,可以用來(lái)進(jìn)行數(shù)據(jù)提取轉(zhuǎn)化加載(ETL)甲棍,這是一種可以存儲(chǔ)简识、查詢和分析存儲(chǔ)在 Hadoop 中的大規(guī)模數(shù)據(jù)的機(jī)制。Hive 定義了簡(jiǎn)單的類 SQL 查詢語(yǔ)言,稱為 QL七扰,它允許熟悉 SQL 的用戶查詢數(shù)據(jù)奢赂。同時(shí),這個(gè)語(yǔ)言也允許熟悉 MapReduce 開發(fā)者的開發(fā)自定義的 mapper 和 reducer 來(lái)處理內(nèi)建的 mapper 和 reducer 無(wú)法完成的復(fù)雜的分析工作颈走。
- Hive是SQL解析引擎膳灶,它將SQL語(yǔ)句轉(zhuǎn)譯為M/R Job然后再Hadoop執(zhí)行
- QL語(yǔ)句在底層被轉(zhuǎn)化為相應(yīng)的MapReduce操作
- Hive的表其實(shí)就是HDFS的目錄,按表名把文件夾分開立由。如果是分區(qū)表轧钓,分區(qū)值是子文件夾,可以直接在M/R Job里使用這些數(shù)
通俗來(lái)講就是傳統(tǒng)mysql無(wú)法處理大數(shù)據(jù)锐膜,而大數(shù)據(jù)文件系統(tǒng)HDFS不能使用SQL毕箍,Hive就是一種可以用類SQL語(yǔ)句對(duì)大數(shù)據(jù)文件系統(tǒng)中的結(jié)構(gòu)化數(shù)據(jù)進(jìn)行操作的工具
Hive的系統(tǒng)架構(gòu)
(JobTracker是Hadoop1.x中的ResouceManager + AppMaster
TaskTracker相當(dāng)于NodeManager + YarnChild)
- 用戶接口,包括CLI道盏,JDBC/ODBC霉晕,WebUI
- metastore,Hive將元數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中(metastore)捞奕,目前只支持 mysql牺堰、derby(Derby引擎的缺點(diǎn):一次只能打開一個(gè)會(huì)話。使用Mysql作為外置存儲(chǔ)引擎颅围,多用戶同時(shí)訪問)伟葫。Hive 中的元數(shù)據(jù)包括表名、列院促、分區(qū)及其屬性筏养、表的屬性(是否為外部表等)、表數(shù)據(jù)所在目錄等
- Driver 解釋器常拓、編譯器渐溶、優(yōu)化器完成 HQL 查詢語(yǔ)句從詞法分析、語(yǔ)法分析弄抬、編譯茎辐、優(yōu)化以及查詢計(jì)劃(plan)的生成。生成的查詢計(jì)劃存儲(chǔ)在HDFS 中掂恕,并在隨后有 MapReduce 調(diào)用執(zhí)行
- Hive的數(shù)據(jù)存儲(chǔ)在HDFS中拖陆,大部分的查詢由MapReduce完成(包含 * 的查詢,比如select * from tb不會(huì)生成MapReduce任務(wù))
Hive和普通關(guān)系數(shù)據(jù)庫(kù)的異同
- 查詢語(yǔ)言懊亡。由于SQL被廣泛的應(yīng)用在數(shù)據(jù)倉(cāng)庫(kù)中依啰,因此,專門針對(duì)Hive的特性設(shè)計(jì)了類SQL的查詢語(yǔ)言HQL店枣。熟悉SQL開發(fā)就很容易入手Hive開發(fā)速警。
- 數(shù)據(jù)倉(cāng)庫(kù)位置叹誉。Hive是建立在Hadoop之上的,所有Hive的數(shù)據(jù)都是存儲(chǔ)在HDFS中的闷旧。而數(shù)據(jù)庫(kù)則可以將數(shù)據(jù)保存在塊設(shè)備或者本地文件系統(tǒng)中桂对。
- 數(shù)據(jù)格式。 Hive中沒有定義專門的數(shù)據(jù)格式鸠匀,數(shù)據(jù)格式可以由用戶指定,用戶定義數(shù)據(jù)格式需要指定三個(gè)屬性逾柿,列分隔符(通常為空格)缀棍、行分隔符(“\n”)以及讀取文件數(shù)據(jù)的方法(Hive中默認(rèn)有三個(gè)文件格式TextFile,SequenceFile以及RCFile)。由于在加載數(shù)據(jù)的過程中机错,不需要從用戶數(shù)據(jù)格式到Hive定義的數(shù)據(jù)格式的轉(zhuǎn)換爬范,因此,Hive在加載的過程中不會(huì)對(duì)數(shù)據(jù)本身進(jìn)行任何修改弱匪,而只是將數(shù)據(jù)內(nèi)容復(fù)制或者移動(dòng)到相應(yīng)的HDFS目錄中青瀑。
- 數(shù)據(jù)更新。由于Hive是針對(duì)數(shù)據(jù)倉(cāng)庫(kù)應(yīng)用設(shè)計(jì)的萧诫,而數(shù)據(jù)倉(cāng)庫(kù)的內(nèi)容是讀多寫少的斥难。因此,Hive中不支持對(duì)數(shù)據(jù)的改寫和添加帘饶,所有的數(shù)據(jù)都是在加載的時(shí)候中確定好的哑诊。而數(shù)據(jù)庫(kù)中的數(shù)據(jù)通常是需要經(jīng)常進(jìn)行修改的,因此可以使用 INSERT INTO … VALUES 添加數(shù)據(jù)及刻,使用 UPDATE … SET修改數(shù)據(jù)镀裤。
- 索引。Hive在加載數(shù)據(jù)的過程中不會(huì)對(duì)數(shù)據(jù)進(jìn)行任何處理缴饭,甚至不會(huì)對(duì)數(shù)據(jù)進(jìn)行掃描暑劝,因此也沒有對(duì)數(shù)據(jù)中的某些Key建立索引。Hive要訪問數(shù)據(jù)中滿足條件的特定值時(shí)颗搂,需要暴力掃描整個(gè)數(shù)據(jù)担猛,因此訪問延遲較高。由于 MapReduce 的引入丢氢, Hive 可以并行訪問數(shù)據(jù)毁习,因此即使沒有索引,對(duì)于大數(shù)據(jù)量的訪問卖丸,Hive 仍然可以體現(xiàn)出優(yōu)勢(shì)纺且。數(shù)據(jù)庫(kù)中,通常會(huì)針對(duì)一個(gè)或者幾個(gè)列建立索引稍浆,因此對(duì)于少量的特定條件的數(shù)據(jù)的訪問载碌,數(shù)據(jù)庫(kù)可以有很高的效率猜嘱,較低的延遲。由于數(shù)據(jù)的訪問延遲較高嫁艇,決定了 Hive 不適合在線數(shù)據(jù)查詢朗伶。
- 執(zhí)行。Hive中大多數(shù)查詢的執(zhí)行是通過 Hadoop 提供的 MapReduce 來(lái)實(shí)現(xiàn)的(類似 select * from tbl的查詢不需要MapReduce)步咪。而數(shù)據(jù)庫(kù)通常有自己的執(zhí)行引擎论皆。
- 執(zhí)行延遲。Hive 在查詢數(shù)據(jù)的時(shí)候猾漫,由于沒有索引点晴,需要掃描整個(gè)表,因此延遲較高悯周。另外一個(gè)導(dǎo)致 Hive 執(zhí)行延遲高的因素是 MapReduce框架粒督。由于MapReduce 本身具有較高的延遲,因此在利用MapReduce 執(zhí)行Hive查詢時(shí)禽翼,也會(huì)有較高的延遲屠橄。相對(duì)的,數(shù)據(jù)庫(kù)的執(zhí)行延遲較低闰挡。當(dāng)然锐墙,這個(gè)低是有條件的,即數(shù)據(jù)規(guī)模較小长酗,當(dāng)數(shù)據(jù)規(guī)模大到超過數(shù)據(jù)庫(kù)的處理能力的時(shí) 候贮匕,Hive的并行計(jì)算顯然能體現(xiàn)出優(yōu)勢(shì)。
- 可擴(kuò)展性花枫。由于Hive是建立在Hadoop之上的刻盐,因此Hive的可擴(kuò)展性是和Hadoop的可擴(kuò)展性是一致的。而數(shù)據(jù)庫(kù)由于 ACID 語(yǔ)義的嚴(yán)格限制劳翰,擴(kuò)展行非常有限敦锌。目前最先進(jìn)的并行數(shù)據(jù)庫(kù) Oracle 在理論上的擴(kuò)展能力也只有100臺(tái)左右。
- 規(guī)模佳簸。由于Hive建立在集群上并可以利用MapReduce進(jìn)行并行計(jì)算乙墙,因此可以支持很大規(guī)模的數(shù)據(jù);對(duì)應(yīng)的生均,數(shù)據(jù)庫(kù)可以支持的數(shù)據(jù)規(guī)模較小听想。
Hive數(shù)據(jù)類型
在對(duì)Hive進(jìn)行操作之前,首先要明白Hive數(shù)據(jù)類型有哪些马胧。
- tinyint/smallint/int/bigint
- float/double
- boolean
- DECIMAL -用戶可以指定范圍和小數(shù)點(diǎn)位數(shù)
- STRING -在特定的字符集中的一個(gè)字符串序列
- VARCHAR -在特定的字符集中的一個(gè)有最大長(zhǎng)度限制的字符串序列
- CHAR -在特定的字符集中的一個(gè)指定長(zhǎng)度的字符串序列
- BINARY -一個(gè)二進(jìn)制位序列
- 結(jié)構(gòu)體類型(Stuct): 使用點(diǎn)(.)來(lái)訪問類型內(nèi)部的元素汉买。例如,有一列c佩脊,它是一個(gè)結(jié)構(gòu)體類型{a INT; b INT}蛙粘,字段a可以使用表達(dá)式c.a來(lái)訪問垫卤。
- Map(key-value鍵值對(duì)):使用['元素名']來(lái)訪問元素。例如出牧,有一個(gè)MapM穴肘,包含'group'->gid的映射,則gid的值可以使用M['group']來(lái)訪問舔痕。
- 數(shù)組:數(shù)組中的元素是相同的類型评抚。可以使用[n]來(lái)訪問數(shù)組元素伯复,n是數(shù)組下標(biāo)慨代,以0開始。例如有一個(gè)數(shù)組A边翼,有元素['a','b','c'],則A[1]返回'b'鸣剪。
Hive實(shí)踐操作
配置Hive
上一階段配置CDH的時(shí)候就一起配置了Hive组底,也可以使用Apache Hadoop單獨(dú)配置。
這里出現(xiàn)一個(gè)問題筐骇,hive啟動(dòng)不起來(lái)债鸡,一直等待在界面沒反應(yīng),去master:10002查看了一下hive服務(wù)铛纬,發(fā)現(xiàn)無(wú)響應(yīng)厌均,說明hive沒有啟動(dòng)起來(lái),所以去管理界面查看情況告唆,運(yùn)行狀態(tài)不良
建立內(nèi)表、外表
- 在導(dǎo)入數(shù)據(jù)到外部表僧凤,數(shù)據(jù)并沒有移動(dòng)到自己的數(shù)據(jù)倉(cāng)庫(kù)目錄下(如果指定了location的話)畜侦,也就是說外部表中的數(shù)據(jù)并不是由它自己來(lái)管理的!而內(nèi)部表則不一樣躯保;
- 在刪除內(nèi)部表的時(shí)候旋膳,Hive將會(huì)把屬于表的元數(shù)據(jù)和數(shù)據(jù)全部刪掉;而刪除外部表的時(shí)候途事,Hive僅僅刪除外部表的元數(shù)據(jù)溺忧,數(shù)據(jù)是不會(huì)刪除的咏连!
- 在創(chuàng)建內(nèi)部表或外部表時(shí)加上location 的效果是一樣的,只不過表目錄的位置不同而已鲁森,加上partition用法也一樣祟滴,只不過表目錄下會(huì)有分區(qū)目錄而已,load data local inpath直接把本地文件系統(tǒng)的數(shù)據(jù)上傳到hdfs上歌溉,有l(wèi)ocation上傳到location指定的位置上垄懂,沒有的話上傳到hive默認(rèn)配置的數(shù)據(jù)倉(cāng)庫(kù)中。
數(shù)據(jù)選擇Sogou用戶查詢語(yǔ)料信息痛垛,下載之后由于編碼有問題草慧,還需要進(jìn)行編碼轉(zhuǎn)為為utf8。
iconv -f gbk -t utf8 -c SogouQ.sample > SogouQ.sample2
因?yàn)橥獗斫⑿枰鞔_行列分隔符匙头,而數(shù)據(jù)當(dāng)中存在列分隔符不一致的情況漫谷,需要利用sed命令進(jìn)行轉(zhuǎn)換。
cat SogouQ.sample2 | sed -e 's/ /\t/g' >>Sogou
可以將空格替換為\t蹂析,替換規(guī)則為sed 's/要被取代的字串/新的字串/g'
再配合管道和追加到Sogou文件中就完成了替換舔示。-
首先和mysql一樣需要?jiǎng)?chuàng)建數(shù)據(jù)庫(kù)
-
建立對(duì)應(yīng)的外表
-
同時(shí)建立內(nèi)表
這里指定了外部表的具體存儲(chǔ)位置為/tmp/sogou文件夾,方便以后查看电抚。由于原始數(shù)據(jù)里行分隔符為\t惕稻,所以創(chuàng)建時(shí)要匹配為\t。
- 導(dǎo)入數(shù)據(jù)到表
load data local inpath '/usr/tmp/Sogou' into table sogou;
這里的路徑指的是本機(jī)上的文件路徑蝙叛。
-
查看導(dǎo)入數(shù)據(jù)情況
外表和內(nèi)表都導(dǎo)入成功了俺祠,那么來(lái)看一下兩個(gè)表在hdfs中存儲(chǔ)位置有什么區(qū)別。
-
刪除表
可以看到內(nèi)表的表信息和數(shù)據(jù)全部都被刪除了借帘。
然而外部表的數(shù)據(jù)全部都還在蜘渣。
hive sql
hive的大多數(shù)查詢都會(huì)轉(zhuǎn)化為MapReduce程序,可以導(dǎo)master:8088查看相應(yīng)的MapReduce程序肺然。
- group by
group by和sql里面的使用方法相似宋梧,都是用于對(duì)某個(gè)或多個(gè)列的值進(jìn)行分組查詢。
select rank,count(url) from sogou group by rank having rank < 10;
用于查詢排名前10的url個(gè)數(shù)
- select后面的非聚合列必須出現(xiàn)在group by中(比如上面的rank)
- 除了普通列就是一些聚合操作(比如上面的count(rank))
- Order by
Order by會(huì)對(duì)輸入做全局排序狰挡,因此只有一個(gè)Reducer(多個(gè)Reducer無(wú)法保證全局有序)捂龄,然而只有一個(gè)Reducer,會(huì)導(dǎo)致當(dāng)輸入規(guī)模較大時(shí)加叁,消耗較長(zhǎng)的計(jì)算時(shí)間倦沧。
Order by語(yǔ)法如下:
select col,col2...
from tableName
where condition
order by col1,col2 [asc|desc]
- order by后面可以有多列進(jìn)行排序,默認(rèn)按字典排序它匕。
- order by為全局排序展融。
- order by需要reduce操作,且只有一個(gè)reduce豫柬,無(wú)法配置(因?yàn)槎鄠€(gè)reduce無(wú)法完成全局排序)告希。
select * from sogou order by rank desc limit 5;
獲取排名前5的所有信息
- sort by
hive使用order by會(huì)默認(rèn)設(shè)置reduce的個(gè)數(shù)=1扑浸,既然reducer的個(gè)數(shù)都是1了,結(jié)果自然全排序燕偶!但是reducer個(gè)數(shù)為1會(huì)導(dǎo)致效率非常的低喝噪,所以提供了一個(gè)新的排序方式sort by。
它會(huì)保證每個(gè)reducer的輸出文件是有序的指么,要想實(shí)現(xiàn)全排序酝惧,還得加一個(gè)order by的過程,就是對(duì)sort by的reduce輸出結(jié)果再進(jìn)行一次排序伯诬。要想用hive實(shí)現(xiàn)全排序:要么用order by晚唇,但這樣默認(rèn)了reducer個(gè)數(shù)為1,效率低下盗似。要么用sort by+order by哩陕,sort by過程可以設(shè)置reducer個(gè)數(shù)(n),order by過程用n個(gè)reducer的輸出文件進(jìn)行一次全排序赫舒,得到最終的結(jié)果悍及。
select * from sogou sort by rank desc limit 5;
這里是對(duì)rank進(jìn)行排序,但是不是全局排序号阿,而是對(duì)每一個(gè)reducer內(nèi)部進(jìn)行排序并鸵,那么怎樣hive如何將所有數(shù)據(jù)劃分給若干個(gè)reducer呢鸳粉?這就要用到下面的distribute了扔涧。 - distribute by
distribute by是控制map的輸出在reducer是如何劃分的。hive會(huì)根據(jù)distribute by后面列届谈,對(duì)應(yīng)reduce的個(gè)數(shù)進(jìn)行分發(fā)枯夜,默認(rèn)是采用hash算法。舉個(gè)例子
select * from sogou distribute by rank sort by rank,time desc limit 5;
表示將rank哈希后(這里并不是簡(jiǎn)單的把rank相同的數(shù)據(jù)劃分為一個(gè)cluster艰山,而是對(duì)rank值哈希后再對(duì)cluster個(gè)數(shù)進(jìn)行求余)相同的數(shù)據(jù)全部送到一個(gè)reducer進(jìn)行處理湖雹,這就是因?yàn)橹付薲istribute by rank,再配合sort by這樣的話就可以統(tǒng)計(jì)出每個(gè)rank排名中所有數(shù)據(jù)的時(shí)間順序了曙搬。這里需要注意的是distribute by必須要寫在sort by之前摔吏。
- cluster by
cluster by的功能就是distribute by和sort by相結(jié)合,如下2組語(yǔ)句是等價(jià)的:
select * from sogou cluster by rank
select * from sogou cluster by distribute by rank sort by rank
注意被cluster by指定的列只能是升序纵装,不能指定asc和desc征讲。
Java、Python調(diào)用Hive
和下面Python調(diào)用一樣橡娄,只需要下載相應(yīng)的jar诗箍,跟著官方文檔即可。
pyhive
首先安裝連接hive需要的依賴
pip install sasl
pip install thrift
pip install thrift-sasl
pip install PyHive
然后就可以按照固定的格式開啟連接了
from pyhive import hive
conn = hive.Connection(host='192.168.233.100',port=10000,username='root',database='mytest')
cursor = conn.cursor()
cursor.execute('select * from sogou limit 10')
for result in cursor.fetchall():
print(result)
但是報(bào)錯(cuò)了
thrift.transport.TTransport.TTransportException: Could not start SASL: b'Error in sasl_client_start (-4) SASL(-4): no mechanism available: Unable to find a callback: 2'
查看hive的日志
java.lang.RuntimeException: org.apache.thrift.transport.TSaslTransportException: No data or no sasl data in the stream
網(wǎng)上找了一下也沒什么好的解決方案挽唉,看這個(gè)報(bào)錯(cuò)信息應(yīng)該是windows系統(tǒng)底層的問題滤祖,所以換到centos里執(zhí)行剛剛的python程序筷狼。
成功連接hive并得到查詢結(jié)果。
Java Hive
UDF匠童、UDAF埂材、UDTF
Hive中,除了提供豐富的內(nèi)置函數(shù)之外俏让,還允許用戶使用Java開發(fā)自定義的UDF函數(shù)楞遏。UDF有幾種:
- (普通)UDF:操作作用于單個(gè)數(shù)據(jù)行,且產(chǎn)生一個(gè)數(shù)據(jù)行作為輸出首昔。
- 用戶自定義聚合函數(shù)(UDAF):接受多個(gè)輸入數(shù)據(jù)行寡喝,并產(chǎn)生一個(gè)輸出數(shù)據(jù)行。
- 用戶自定義生表函數(shù)(UDTF):接受一個(gè)數(shù)據(jù)行勒奇,然后返回產(chǎn)生多個(gè)數(shù)據(jù)行
開發(fā)自定義UDF函數(shù)有兩種方式
繼承org.apache.hadoop.hive.ql.exec.UDF
繼承org.apache.hadoop.hive.ql.udf.generic.GenericUDF预鬓;
如果是針對(duì)簡(jiǎn)單的數(shù)據(jù)類型(比如String、Integer等)可以使用UDF赊颠,如果是針對(duì)復(fù)雜的數(shù)據(jù)類型(比如Array格二、Map、Struct等)竣蹦,可以使用GenericUDF顶猜,另外,GenericUDF還可以在函數(shù)開始之前和結(jié)束之后做一些初始化和關(guān)閉的處理操作痘括。
UDF
使用自定義UDF時(shí)长窄,只需要繼承org.apache.hadoop.hive.ql.exec.UDF,并定義public Object evaluate(Object args) {} 方法即可纲菌。例如:
package li;
import org.apache.hadoop.hive.ql.exec.UDF;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HashMd5 {
public String evaluate(String password) {
try {
// 得到一個(gè)信息摘要器
MessageDigest digest = MessageDigest.getInstance("md5");
byte[] result = digest.digest(password.getBytes());
StringBuffer buffer = new StringBuffer();
// 把每一個(gè)byte 做一個(gè)與運(yùn)算 0xff;
for (byte b : result) {
// 與運(yùn)算
int number = b & 0xff;// 加鹽
String str = Integer.toHexString(number);
if (str.length() == 1) {
buffer.append("0");
}
buffer.append(str);
}
// 標(biāo)準(zhǔn)的md5加密后的結(jié)果
return buffer.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
}
evaluate方法就是要進(jìn)行處理的函數(shù)內(nèi)容挠日。這個(gè)函數(shù)的意思是將輸入的內(nèi)容轉(zhuǎn)為它的MD5值。
用IDEA把剛剛寫好的Java文件打成jar包(這里特別需要注意編譯成jar包的環(huán)境JDK要和hive平臺(tái)的JDK一致翰舌,所以我把JDK變?yōu)榱?.6)
然后就可以在hive交互界面使用命令
add jar /usr/tmp/myudf.jar
這里的路徑是把jar包存放在linux文件下的路徑嚣潜。
接著生成函數(shù)方法
create temporary function md5 as 'li.HashMd5';
因?yàn)槲抑皇菫榱藴y(cè)試,所以用的temporary椅贱,表示該方法的作用時(shí)間只是這次session懂算,as后面跟著的是你寫入自定義函數(shù)的類的完整類名
隨后就可以寫測(cè)試hive sql來(lái)看看是否成功了。
select rank,md5(rank) from sogou limit 10;
這里第一次報(bào)錯(cuò)了
Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:dr
錯(cuò)誤顯示想要訪問/user下的內(nèi)容庇麦,但是權(quán)限不夠计技,因?yàn)槲沂窃趓oot用戶下進(jìn)入的hive交互界面,所以有些文件不能執(zhí)行操作女器,所以切換至hdfs用戶就可以了酸役。
這里可以看到同樣的值得到了同樣的MD5值,所以驗(yàn)證成功。
UDAF
UDAF 接受多個(gè)輸入數(shù)據(jù)行涣澡,并產(chǎn)生一個(gè)輸出數(shù)據(jù)行贱呐。
一個(gè)計(jì)算函數(shù)必須實(shí)現(xiàn)以下5個(gè)方法:
- init(): 該方法負(fù)責(zé)初始化計(jì)算函數(shù)并重設(shè)它的內(nèi)部狀態(tài) 。
- iterate(): 每次對(duì)一個(gè)新值進(jìn)行聚合計(jì)算時(shí)會(huì)調(diào)用該方法入桂。
- terminatePartial(): Hive需要部分聚合結(jié)果時(shí)會(huì)調(diào)用該方法奄薇。
- merge(): Hive需要將部分聚合結(jié)果和另外部分聚合結(jié)果合并時(shí)會(huì)調(diào)用該方法。
-
terminate(): 需要最終結(jié)果時(shí)會(huì)調(diào)用該方法
和上面自定義UDF的方法類似抗愁,也是編寫代碼后臺(tái)添加功能馁蒂。
package li;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.FloatWritable;
@SuppressWarnings("deprecation")
public class Mean extends UDAF {
public static class MeanFloatUDAFEvaluator implements UDAFEvaluator {
public static class PartialResult {
float sum;
long count;
}
private PartialResult partialresult;
@Override
public void init() {
// TODO Auto-generated method stub
partialresult = null;
}
public boolean iterate(FloatWritable value) {
if (value == null) {
return true;
}
if (partialresult == null) {
partialresult = new PartialResult();
}
partialresult.sum += value.get();
++partialresult.count;
return true;
}
public PartialResult terminatePartial() {
return partialresult;
}
public boolean merge(PartialResult other) {
if (other == null) {
return true;
}
if (partialresult == null) {
partialresult = new PartialResult();
}
partialresult.sum += other.sum;
partialresult.count += other.count;
return true;
}
public FloatWritable terminate() {
if (partialresult == null) {
return null;
}
return new FloatWritable(partialresult.sum / partialresult.count);
}
}
}
然后添加jar和臨時(shí)方法
add jar /usr/tmp/myudf.jar
create temporary function my_mean as 'li.Mean';
可以再show functions里面看到自己的方法了。
分區(qū)蜘腌、分桶
Hive使用select語(yǔ)句進(jìn)行查詢的時(shí)候一般會(huì)掃描整個(gè)表內(nèi)容沫屡,會(huì)消耗很多時(shí)間做沒必要的工作。Hive可以在創(chuàng)建表的時(shí)候指定分區(qū)空間撮珠,這樣在做查詢的時(shí)候就可以很好的提高查詢的效率沮脖。
Hive中的每個(gè)分區(qū)對(duì)應(yīng)數(shù)據(jù)庫(kù)中相應(yīng)分區(qū)列的一個(gè)索引,每個(gè)分區(qū)對(duì)應(yīng)著表下的一個(gè)目錄芯急,在HDFS上的表現(xiàn)形式與表在HDFS上的表現(xiàn)形式相同勺届,都是以子目錄的形式存在。
- 創(chuàng)建分區(qū)表
create table t1(
> id int,
> name string
> )
> partitioned by (pt varchar(8))
> ;
這里表示將字段pt作為分區(qū)的目標(biāo)字段
- 裝載數(shù)據(jù)進(jìn)分區(qū)表
首先創(chuàng)建測(cè)試數(shù)據(jù)data
1,a
2,b
3,c
load data local inpath '/usr/tmp/data' overwrite into table t1 partition (pt='001');
所有數(shù)據(jù)都被裝載到分區(qū)001中去了娶耍;再次將數(shù)據(jù)裝載進(jìn)分區(qū)002中去免姿。
load data local inpath '/usr/tmp/data' overwrite into table t1 partition (pt='002');
通過這里可以看出成功將數(shù)據(jù)裝載進(jìn)了不同的分區(qū),下面再看一下在HDFS中分區(qū)是如何實(shí)現(xiàn)的榕酒。
進(jìn)入到hive默認(rèn)存儲(chǔ)地址/user/hive/warehouse
在這里我們可以清晰的看到hive首先為這個(gè)數(shù)據(jù)庫(kù)創(chuàng)建了一個(gè)文件夾胚膊,然后為每一個(gè)分區(qū)創(chuàng)建一個(gè)子目錄,將屬于各自分區(qū)的數(shù)據(jù)就存放在各自分區(qū)的目錄下奈应。
也可以查看有哪些分區(qū)和刪除指定分區(qū)(會(huì)同時(shí)刪除分區(qū)中數(shù)據(jù))
hive>partitions t1;
OK
pt=001
pt=002
hive> alter table t1 drop partition(pt=001);
Dropped the partition pt=001
OK
對(duì)于每一個(gè)表或者是分區(qū)澜掩,Hive可以進(jìn)一步組織成桶购披,也就是說桶是更為細(xì)粒度的數(shù)據(jù)范圍劃分杖挣。Hive是針對(duì)某一列進(jìn)行分桶。Hive采用對(duì)列值哈希刚陡,然后除以桶的個(gè)數(shù)求余的方式?jīng)Q定該條記錄存放在哪個(gè)桶中惩妇。分桶的好處是可以獲得更高的查詢處理效率。使取樣更高效筐乳。分桶比分區(qū)歌殃,更高的查詢效率。
- 建立桶表
create table bucket_test(
id int,
name string
)
clustered by(id) into 4 buckets
row format delimited fields terminated by '\t'
sorted as textfile;
裝入數(shù)據(jù)
load data local inpath '/usr/tmp/data' overwrite into table bucket_test;
數(shù)據(jù)成功裝入后蝙云,就去目錄中看一看桶的結(jié)構(gòu)氓皱。發(fā)現(xiàn)分桶沒有成功。查了一下資料,說是設(shè)置hive分桶為true
set hive.enforce.bucketing = true;
但是還是不行波材。仔細(xì)思考了一下股淡,應(yīng)該是導(dǎo)入數(shù)據(jù)的方式有問題,我這里用load導(dǎo)入數(shù)據(jù)使得hive可能不會(huì)逐一檢索數(shù)據(jù)并根據(jù)哈希值存入桶廷区,應(yīng)該用insert方式導(dǎo)入數(shù)據(jù)唯灵,hive才會(huì)逐一根據(jù)數(shù)據(jù)指定列的哈希值存入不同的桶。
insert overwrite table bucketed_user
> select id,name from t1;
這樣就將數(shù)據(jù)庫(kù)分為了4個(gè)桶隙轻。仔細(xì)觀察會(huì)發(fā)現(xiàn)每個(gè)桶不是文件夾埠帕,而是文件,這點(diǎn)和分區(qū)不一樣玖绿。當(dāng)從桶表中進(jìn)行查詢時(shí)敛瓷,hive會(huì)根據(jù)分桶的字段進(jìn)行計(jì)算分析出數(shù)據(jù)存放的桶中,然后直接到對(duì)應(yīng)的桶中去取數(shù)據(jù)斑匪,這樣做就很好的提高了效率琐驴。
- 索引和分區(qū)最大的區(qū)別就是索引不分割數(shù)據(jù)庫(kù),分區(qū)分割數(shù)據(jù)庫(kù)秤标。
- 分區(qū)和分桶最大的區(qū)別就是分桶隨機(jī)分割數(shù)據(jù)庫(kù)绝淡,分區(qū)是非隨機(jī)分割數(shù)據(jù)庫(kù)。
- 其次兩者的另一個(gè)區(qū)別就是分桶是對(duì)應(yīng)不同的文件(細(xì)粒度)苍姜,分區(qū)是對(duì)應(yīng)不同的文件夾(粗粒度)牢酵。