Hive基础
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
Hive架構(gòu)簡介
? ? 下圖是hive的架構(gòu)圖
命令執(zhí)行
所有的命令和查詢都會進(jìn)入到Driver,通過這個(gè)模塊進(jìn)行解析編譯,對需求的計(jì)算進(jìn)行優(yōu)化。然后按照指定的步驟執(zhí)行(通常是啟動(dòng)多個(gè)MapReduce任務(wù)(JOB)來執(zhí)行)。當(dāng)需要啟動(dòng) MapReduce任務(wù)(job)時(shí),HIVE 本身不會生成Java MapReduve算法程序。相反,Hive通過一個(gè)表示“JOB執(zhí)行計(jì)劃”的。XML文件驅(qū)動(dòng)執(zhí)行內(nèi)置的、原生的Mapper和Reducer模塊。換句話說,這些通用的模塊函數(shù)類似于微型的語言翻譯程序,二驅(qū)動(dòng)計(jì)算的“語言”是以XML形式編碼的。Hive 通過和JobTracker通信來初始化MapReduve任務(wù)(job),而不必部署在JobTracker所在的管理節(jié)點(diǎn)上執(zhí)行。要處理的數(shù)據(jù)文件是存儲在HDFS中的,而HDFS是由NameNode進(jìn)行管理的。
驅(qū)動(dòng)器:Dirver 包含:解析器、編譯器、優(yōu)化器、執(zhí)行器
解析器:將SQL字符串轉(zhuǎn)換成抽象語法樹AST,這一步一般都是用第三方工具庫完成,比如antlr;對AST語 ? ? ? ? ? ? ? 法樹進(jìn)行分析,比如表否存在、字段是否存在、SQL語義是否有誤。
編譯器:將AST編譯生成邏輯執(zhí)行計(jì)劃。
優(yōu)化器:對邏輯執(zhí)行計(jì)劃進(jìn)行優(yōu)化。
執(zhí)行器:把邏輯執(zhí)行計(jì)劃轉(zhuǎn)換成物理執(zhí)行計(jì)劃。對于hive來說,就是MR/TEZ/Spark;
元數(shù)據(jù)
Metastore是一個(gè)獨(dú)立的關(guān)系型數(shù)據(jù)庫,通常使用MYSQL。Hive 會在其中保存表模式和其他系統(tǒng)元數(shù)據(jù)中的。元數(shù)據(jù)包括表的名字,表的列和分區(qū)及其屬性,表的屬性(是否為外部表等),表的數(shù)據(jù)所在目錄等
?
Hive數(shù)據(jù)類型
????hive基礎(chǔ)數(shù)據(jù)類型
? ? ? hive是用java開發(fā)的,hive里的基本數(shù)據(jù)類型和java的基本數(shù)據(jù)類型也是一一對應(yīng)的,除了string類型。有符號的整數(shù)類型:TINYINT、SMALLINT、INT和BIGINT分別等價(jià)于java的byte、short、int和long原子類型,它們分別為1字節(jié)、2字節(jié)、4字節(jié)和8字節(jié)有符號整數(shù)。Hive的浮點(diǎn)數(shù)據(jù)類型FLOAT和DOUBLE,對應(yīng)于java的基本類型float和double類型。而hive的BOOLEAN類型相當(dāng)于java的基本數(shù)據(jù)類型boolean。
????hive復(fù)雜數(shù)據(jù)類型
? ? ? ?包括ARRAY,MAP,STRUCT,UNION。這些復(fù)雜類型是由基礎(chǔ)類型組成的。
? ? ? ?ARRAY:ARRAY類型是由一系列同樣數(shù)據(jù)類型元素組成的,這些元素能夠通過下標(biāo)來訪問。比方有一個(gè)ARRAY類型的變量fruits。它是由[‘a(chǎn)pple’,’orange’,’mango’]組成,那么能夠通過fruits[1]來訪問orange。
? ? ? ?MAP:MAP包括key->value鍵值對。能夠通過key來訪問元素。比方userlist是一個(gè)map類型(當(dāng)中username是key。password是value),那么我們能夠通過userlist[username]來得到這個(gè)用戶相應(yīng)的password.。
? ? ? STRUCT:STRUCT能夠包括不同數(shù)據(jù)類型的元素。這些元素能夠通過點(diǎn)的方式來得到,比方user是一個(gè)STRUCT類型,那么能夠通過user.address得到這個(gè)用戶的地址。
????????COLLECTION?ITEMS?TERMINATED?BY?',' ? ?//集合元素分隔符
????????MAP?KEYS?TERMINATED?BY?' : ' ? ? ? ? ? ? ? ?//MAP數(shù)據(jù)類型key:value分割符
Hive表類型
????? 內(nèi)部表
????????????內(nèi)部表也稱之為MANAGED_TABLE;默認(rèn)存儲在/user/hive/warehouse下,也可以通過location指定;刪除表時(shí),會刪除表數(shù)據(jù)以及元數(shù)據(jù);
????? ? ?create table if not exists...
? ? ? ?外部表
???????外部表稱之為EXTERNAL_TABLE在創(chuàng)建表時(shí)可以自己指定目錄位置(LOCATION);刪除表時(shí),只會刪除元數(shù)據(jù)不會刪除表數(shù)據(jù);
????? ?create EXTERNAL table if not exists...
????? ?加載數(shù)據(jù)
????????? ? 注意 導(dǎo)入的路徑必須是hive用戶有訪問權(quán)限的路徑,否則會報(bào)找不到文件錯(cuò)誤
? ? ? ? ? ?(1)?HDFS上導(dǎo)入數(shù)據(jù)到Hive表
? ? ? ? ?? ?(2) 從本地路徑導(dǎo)入數(shù)據(jù)到Hive表
load?data local inpath 'wyp.txt' into table test ;#使用分區(qū) load?data local inpath '/your/path/test.txt' overwrite into table test partition (age='25')????????????(3)?從別的表查詢加載到hive表
?????????????靜態(tài)分區(qū)
insert into table test partition (age='25') select id, name, tel from wyp;????????? ? ?動(dòng)態(tài)分區(qū)
set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; insert overwrite table test PARTITION (age) select id, name, tel, age from wyp;????insert into table和insert overwrite table的區(qū)別:后者會覆蓋相應(yīng)數(shù)據(jù)目錄下的數(shù)據(jù)將。
????創(chuàng)建相似表
create table table_name like other_table_name location "xxxxx"????查詢數(shù)據(jù)輸出到本地目錄
INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a WHERE a.ds='<DATE>';select *from emp distribute by deptno sort by empno asc ;
cluster by ?= distribute by 和 sort by 值相同。
Hive UDF編程
????UDF(user defined function).hive的UDF包含三種:UDF支持一個(gè)輸入產(chǎn)生一個(gè)輸出,UDTF支持一個(gè)輸入多個(gè)輸出輸出(一行變多行),UDAF支持多輸入一輸出(多行變一行)。
? ?UDF 簡單實(shí)現(xiàn)
? 編程步驟:
????1、繼承org.apache.hadoop.hive.ql.UDF
????2、需要實(shí)現(xiàn)evaluate函數(shù); evaluate函數(shù)支持重載;
? 注意事項(xiàng):
????1、 UDF必須要有返回類型,可以返回null,但是返回類型不能為void;
????2、 UDF中常用Text/LongWritable等類型,不推薦使用java類型;
? ? 官網(wǎng)demo: ?https://cwiki.apache.org/confluence/display/Hive/HivePlugins
? 使用UDF非常簡單,只需要繼承org.apache.hadoop.hive.ql.exec.UDF,并定義public Object evaluate(Object args) {} 方法即可。
? ? ?比如,下面的UDF函數(shù)實(shí)現(xiàn)了對一個(gè)String類型的字符串取HashMD5:
package?com.lxw1234.hive.udf;import?org.apache.hadoop.hbase.util.Bytes; import?org.apache.hadoop.hbase.util.MD5Hash; import?org.apache.hadoop.hive.ql.exec.UDF;public?class?HashMd5?extends?UDF?{public?String?evaluate(String?cookie)?{return?MD5Hash.getMD5AsHex(Bytes.toBytes(cookie));}public?String?evaluate(String?cookie1,String cookie2)?{return?MD5Hash.getMD5AsHex(Bytes.toBytes(cookie1,cookie2));}}將上面的HashMd5類打成jar包,udf.jar
使用時(shí)候,在Hive命令行執(zhí)行:
hive> add jar file:///tmp/udf.jar; hive> CREATE temporary?function?str_md5?as?'com.lxw1234.hive.udf.HashMd5'; hive> select?str_md5(‘lxw1234.com’)?from?dual;?
? ? Transform
? ? ?Hive中的TRANSFORM:使用腳本完成Map/Reduce。
hive> add file python文件路徑 hive> SELECTTRANSFORM(p.joint_attr_values,?p.collect_product_id,?p.released_id)??USING?'python?split_product_attrs.py'??as?(custom_attr?,?custom_attr_value,?collect_product_id,?released_product_id)??from???(??這里應(yīng)該是另外一個(gè)select語句,用于Transform的輸入,最好是一一對應(yīng)的,否則會出錯(cuò)??)??? ?注意:python腳本一定要先加載:hive>ADD FILE python_file_path [注意此處的path不要加''上引號]
? ? 下面是python的腳本,用于將三列轉(zhuǎn)換為四列,這里就比較簡單了,主要用于測試,代碼隨便寫了一下
#!/usr/bin/python # #_*_ coding: utf-8 _*_ import sys import datetime # "規(guī)格:RN1-10/50;規(guī)格:RN1-10/50;規(guī)格:RN1-10/50" # ["規(guī)格:RN1-10/51;規(guī)格:RN1-10/52;規(guī)格:RN1-10/53", '11', '22'] # ["規(guī)格", "RN1-10/51", '11', '22'] # ["規(guī)格", "RN1-10/52", '11', '22'] # ["規(guī)格", "RN1-10/53", '11', '22'] for line in sys.stdin: values = line.split('\t') values = [ i.strip() for i in values ] tmp = values[0] key_values = tmp.split(";") for kv in key_values: k = kv.split(":")[0] v = kv.split(":")[1] print '\t'.join([k,v,values[1],values[2]])?
Hive企業(yè)優(yōu)化方案
Hive存儲格式
???1、TEXTFILE ? 默認(rèn)格式,建表時(shí)不指定默認(rèn)為這個(gè)格式,導(dǎo)入數(shù)據(jù)時(shí)會直接把數(shù)據(jù)文件拷貝到hdfs上不進(jìn)行處理。只有TEXTFILE表能直接加載數(shù)據(jù),本地load數(shù)據(jù),和external外部表直接加載運(yùn)路徑數(shù)據(jù),都只能用TEXTFILE表。更深一步,hive默認(rèn)支持的壓縮文件(hadoop默認(rèn)支持的壓縮格式),也只能用TEXTFILE表直接讀取。其他格式不行。可以通過TEXTFILE表加載后insert到其他表中。
? 2、orc?格式。? ?STORED AS ORC?; ?
? 3、parquet 格式。 STORED AS PARQUET ;
?幾種格式的差別 ?http://www.cnblogs.com/juncaoit/p/6067646.html
?
Hive壓縮優(yōu)化
hive壓縮相關(guān)博客??https://yq.aliyun.com/articles/60859
壓縮配置:
?map/reduce?輸出壓縮(一般采用序列化文件存儲)?
set hive.exec.compress.output=true;set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;set mapred.output.compression.type=BLOCK;任務(wù)中間壓縮? ?
set hive.exec.compress.intermediate=true;set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;(常用)set hive.intermediate.compression.type=BLOCK;中間壓縮
中間壓縮就是處理作業(yè)map任務(wù)和reduce任務(wù)之間的數(shù)據(jù),對于中間壓縮,最好選擇一個(gè)節(jié)省CPU耗時(shí)的壓縮方式
<property><name>hive.exec.compress.intermediate</name><value>true</value> </property>hadoop壓縮有一個(gè)默認(rèn)的壓縮格式,當(dāng)然可以通過修改mapred.map.output.compression.codec屬性,使用新的壓縮格式,這個(gè)變量可以在mapred-site.xml?中設(shè)置或者在 hive-site.xml文件。 SnappyCodec?是一個(gè)較好的壓縮格式,CPU消耗較低。
<property><name>mapred.map.output.compression.codec</name><value>org.apache.hadoop.io.compress.SnappyCodec</value> </property>?
?MapReduce中使用壓縮
????
?Hive中 使用壓縮
????????
關(guān)閉推測執(zhí)行
? ? ? ? (1) 修改mapred-site.xml
????????? ? ?mapreduce.map.speculative ? ? false
?????????????mapreduce.reduce.speculative? ? false
??????? (2) 設(shè)置值
????????????set hive.mapred.reduce.tasks.speculative.execution=false;
????? ? (3) set hive.exec.mode.local.auto=true??決定 Hive 是否應(yīng)該自動(dòng)地根據(jù)輸入文件大小,在本地運(yùn)行。
?
Hive 數(shù)據(jù)傾斜解決方案
? ? ? ?Hive join解釋 ?https://www.cnblogs.com/xing901022/p/5804836.html
? ? ? ? 小表 join 大表 ? ? ? ?大表 join 大表 ?方案
? ? (1)Common/Shuffle/Reduce Join ?
? ? ? 普通mapreduce join ,相同key分配到同一個(gè)reducer。
? ? (2) Map Join ?
? ? ? MAPJION會把小表全部讀入內(nèi)存中,在map階段直接拿另外一個(gè)表的數(shù)據(jù)和內(nèi)存中表數(shù)據(jù)做匹配,適用于小表join 大表。
set hive.auto.convert.join=false; set hive.ignore.mapjoin.hint=false;????Sql可以通過使用hint的方式指定join時(shí)使用mapjoin,其中mapjoin選中的表為小表
? ?select?/*+ mapjoin(t1)*/?t1.a,t1.b?from?table?t1?join?table2?t2??on?(?t1.a=t2.a?and t1.time=201108)?
? ? ?Map Join Java實(shí)現(xiàn)??http://www.cnblogs.com/ivanny/p/mapreduce_join.html
? ?(3) ?SMB Join (Sort Merge Bucket Join)
? ? ?使用SMB兩個(gè)表必須使用桶分區(qū),使用 SMB Join 需要如下配置
set hive.enforce.bucketing = true; //強(qiáng)制使用桶表 set hive.auto.convert.sortmerge.join=true; set hive.optimize.bucketmapjoin = true; set hive.optimize.bucketmapjoin.sortedmerge = true;? ?select?/*+ mapjoin(t1)*/?t1.a,t1.b?from?table?t1?join?table2?t2??on?(?t1.a=t2.a?and t1.time=201108)?
? ? 1. 兩個(gè)表關(guān)聯(lián)鍵為id,需要按id分桶并且做排序,小表的分桶數(shù)是大表分桶數(shù)的倍數(shù)。?
????2. 對于map端連接的情況,兩個(gè)表以相同方式劃分桶。處理左邊表內(nèi)某個(gè)桶的 mapper知道右邊表內(nèi)相匹配的行在對應(yīng)的桶內(nèi)。因此,mapper只需要獲取那個(gè)桶 (這只是右邊表內(nèi)存儲數(shù)據(jù)的一小部分)即可進(jìn)行連接。這一優(yōu)化方法并不一定要求 兩個(gè)表必須桶的個(gè)數(shù)相同,兩個(gè)表的桶個(gè)數(shù)是倍數(shù)關(guān)系也可以。
???3. 桶中的數(shù)據(jù)可以根據(jù)一個(gè)或多個(gè)列另外進(jìn)行排序。由于這樣對每個(gè)桶的連接變成了高效的歸并排序(merge-sort), 因此可以進(jìn)一步提升map端連接的效率。
Hive分區(qū)
? ?參數(shù)設(shè)置
#開啟動(dòng)態(tài)分區(qū) set hive.exec.hynamic.partition=true; #注:這個(gè)屬性默認(rèn)是strict,即限制模式,strict是避免全分區(qū)字段是動(dòng)態(tài)的,必須至少一個(gè)分區(qū)字段是指定有值即靜態(tài)的,且必須放在最前面。設(shè)置為nonstrict之后所有的分區(qū)都可以是動(dòng)態(tài)的了。 set hive.exec.dynamic.partition.mode=nonstrict;#注:這個(gè)屬性表示每個(gè)節(jié)點(diǎn)生成動(dòng)態(tài)分區(qū)的最大個(gè)數(shù),默認(rèn)是100 SET hive.exec.max.dynamic.partitions=100000;#注:這個(gè)屬性表示每個(gè)節(jié)點(diǎn)生成動(dòng)態(tài)分區(qū)的最大個(gè)數(shù),默認(rèn)是100 SET hive.exec.max.dynamic.partitions.pernode=100000;#注:這個(gè)屬性表示一個(gè)DML操作可以創(chuàng)建的最大文件數(shù),默認(rèn)是100000 set hive.exec.max.created.files=150000?
建表
create table user_info (user_id int, cid string, ckid string, username string) row format delimited fields terminated by '\t' lines terminated by '\n';1.行格式化 2.字段通過'\t' 分割 3.行通過'\n' 分隔開# flume 收集 建表方案
create table baoertest(user_agent string,user_id bigint,time string) partitioned by (year string, month string, day string) clustered by (user_id) into 5 buckets stored as orc tblproperties("transactional"="true"); ? #使用這個(gè),不能使用insert overwrite,可以使用insert,delete# insert overwrite table 建表方案 ?prestodb可識別
create table baoertest(user_agent string,user_id bigint,time string) partitioned by (year string, month string, day string) clustered by (user_id) into 5 buckets stored as orc;set hive.enforce.bucketing=true;? ? ? ? ? ? ? #? 使用桶,需要強(qiáng)制設(shè)置
set mapreduce.job.reduces=<number>? ?#? 設(shè)置reduces個(gè)數(shù)?
#靜態(tài)分區(qū)
--data.txt--
chrome?? ?112212123?? ?11-12
windows?? ?123123123?? ?11-11
#動(dòng)態(tài)分區(qū)
--data01.txt--
chrome?? ?112212123?? ?11-12?? ?2017?? ?05?? ?21
windows?? ?123123123?? ?11-11?? ?2017?? ?06?? ?19
#查詢使用分區(qū)
?當(dāng)分區(qū)建立后,查詢可直接使用分區(qū)字段 ?
? ? select *from baoertest where year=xxx and month=xxx and day=xxx
#手動(dòng)添加分區(qū)(? 外部表需要手動(dòng)添加分區(qū)? ?)
? ? alter table ?table_xxx ?add partition (dt='2016-09-12');
#手動(dòng)刪除分區(qū)( 刪除分區(qū) 非外部表會同時(shí)刪除分區(qū)的HDFS數(shù)據(jù) )
? ? alter table ?table_xxx ?drop partition (month=2017,month=10,day=21);
#自動(dòng)添加分區(qū),根據(jù)HDFS目錄名
? ??MSCK?REPAIR?TABLE?table_name
? ?執(zhí)行后,Hive會檢測如果HDFS目錄下存在但表的metastore中不存在的partition元信息,更新到metastore中
Hive 修改表
????? ? #修改表的location url
????????alter table test? set location 'hdfs://heracles/user/video-mvc/hive/warehouse/t_m_cc'
轉(zhuǎn)載于:https://my.oschina.net/manmao/blog/1559003
總結(jié)
- 上一篇: 使用nhmicro提供的micro-da
- 下一篇: 蒙提霍尔游戏 python 模拟