《hive編程指南》之hive的數據類型,建立表,外部表,分區,文件類型,字段分割格式。java
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_namemysql
[(col_name data_type [COMMENT col_comment], ...)]git
[COMMENT table_comment]github
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]算法
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]sql
[ROW FORMAT row_format]數據庫
[STORED AS file_format]apache
[LOCATION hdfs_path]編程
[TBLPROPERTIES (property_name=property_value, ...)] 函數
[AS select_statement]
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
LIKE existing_table_name
[LOCATION hdfs_path]
data_type
: primitive_type
| array_type
| map_type
| struct_type
primitive_type
: TINYINT
| SMALLINT
| INT
| BIGINT
| BOOLEAN
| FLOAT
| DOUBLE
| STRING
array_type
: ARRAY < data_type >
map_type
: MAP < primitive_type, data_type >
struct_type
: STRUCT < col_name : data_type [COMMENT col_comment], ...>
row_format
: DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
file_format:
: SEQUENCEFILE
| TEXTFILE
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
這個是我從hive的docs裏面複製出來的,由於我感受我怎麼寫也沒人家寫得好。我最多無非就是在下面舉幾個例子,說明一下使用的方法。
在任意的地方寫好比hive -e ‘show databases’
會執行單引號裏面的命令,而後執完之後會退出,
hive -e ‘show databases’ -S
加了-S會不會有額外的輸出。
首先先看一下數據類型:
TINYINT SMALLINT INT BIGINT固然了都是int類型的,只是範圍不同。
BOOLEAN
FLOAT
DOUBLE
STRING
BINARY
TIMESTAMP
後兩種都是在hive0.8版本後纔有的。固然了還有一些其餘的類型,咱們後面用到再說。
hadoop fs -ls /user/hive/warehouse這個下面保存的是咱們表的實際的數據,這個目錄是咱們默認的目錄。而後表的結構之類的是保存在metadata當中。而metadata又保存在咱們的MySQL當中。
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [LOCATION ‘hdfs_path’]
create external table tab_name location ‘/tmp/ext/tab_name’;
EXTERNAL:做用是能夠指定其餘目錄保存在hdfs中,否則的話就只能保存在默認的位置了。
hdfs_path:是一個已經存在的目錄。不能直接是一個目錄,還得有上級的這麼一個目錄。
而後咱們只要往tab_name裏put咱們的文件,咱們執行
select * from tab_name就會看到數據了.
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
[(col_name data_type [COMMENT col_comment], ...)] //列名:數據類型:列的註釋
[COMMENT table_comment]//整個表的註釋
[PARTITIONED BY//接着解釋一下
舉個例子
drop table tab_name;
create table tab_name (id int , name string) partitioned by (aa string) row format delimited fields terminated by ‘,’location ‘/tmp/ext/tab_name’;
load data local inpath ’/a.txt’ into table tab_name partition(aa=」1」);
load data local inpath '/b.txt' into table user partition (aa="2");
而後注意觀察dfs -ls /tmp/ext/tab_name下有什麼?
咱們發現有一個叫aa=1的目錄,整個目錄下存着剛剛咱們load的文件a.txt;
而後咱們寫select * from tab_name where aa=’1’;
就會查出來該目錄下的數據
若是是select * from tab_name where aa=’2’;
那麼查出來的就是對應的目錄的下的數據
那麼若是是select * from tab_name不寫的話
會把這個表的全部的數據都會查出來。
CLUSTERED BY
這個會是什麼做用呢?
咱們數據仍是使用咱們話單業務產生的數據,
drop table tab_cdr;
create table tab_cdr(oaddr string,oareacode string,daddr string,dareacode string,ts string,type string) row format delimited fields teminated by ‘,’;
load data local inpath ‘/var/www/hadoop/test/output/xx.txt’ into table tab_cdr;(加進去了十萬條數據)
接着咱們建立
set hive.enforce.bucketing=true;//強制使用
create table tab_cdr_buc (oaddr string,oareacode string,daddr string,dareacode string,ts string,type string) clustered by (oaddr ) into 10 buckets;
而後我作一個操做
insert into table tab_cdr_buc select * from tab_cdr;
而後咱們觀察
/tmp/ext/tab_cdr_buc
它下面會有十個文件,規則是根據oaddr的。
這樣作的目的就是爲了提升mapreduce的效率。
總之咱們大致的思路是:把描述信息存到mysql中,這樣咱們隨時隨地在不一樣主機上也能夠訪問hive表,而後咱們把文件要存到hdfs上,這樣就利用到了集羣的威力。這些纔是咱們的目的。
Hive其實跟hibernate很像的,一個表最主要的就是表的描述信息,表的描述信息存在metadata裏面,而咱們的metadata存儲在MySQL的數據庫裏面,這個數據庫的名字會在配置的時候配置。
好比我這次的數據庫的名字叫lixiyuanhive,而後路徑就是(/var/lib/mysql/lixiyuanhive/)咱們表的描述信息室在這兒的。
前面說的咱們把文件存儲在HDFS上,其有默認的路徑是/user/hive/warehouse;固然了咱們在建表的時候也能夠本身指定路徑。
data_type :
primitive_type //基本數據類型
array_type
map_type
struct_type primitive_type ://基本數據類型有
TINYINT
SMALLINT
INT
BIGINT
BOOLEAN
FLOAT
DOUBLE
STRING
BINARY
TIMESTAMP
array_type : ARRAY < data_type > //它的意思是array裏面能夠放data_type類型
那麼data_type的類型有哪些呢,上面有。
map_type : MAP < primitive_type, data_type >//看出來這個須要咱們定義key value
struct_type : STRUCT < col_name : data_type [COMMENT col_comment], ...>
union_type:UNIONTYPE<data_type,data_type,....>
drop table tab_array;
create table tab_array(a array<string> , b array<int>)
row format delimited fields terminated by ‘\t’
collection items terminated by ‘,’;
而後看看咱們準備的數據array.txt:
Rob,bob,stever 1,2,3
Amy,ady 11,22
Jac 11,22,33,44,55
load data local inpath ‘/home/robby/array.txt’ into table tab_array;
固然了咱們能夠select * from tab_array一下
存儲的方式跟咱們在文本里面的時候差很少
若是咱們要想訪問集合那麼
select a[0] from tab_array;
Rob,bob,stever 1,2,3//有0 1 2
Amy,ady 11,22 //有0 1
Jac 11,22,33,44,55//有0
咱們select a[0] from tab_array;的結果就是查到0的
Rob
Amy
Jac
那麼hive也提供了一些函數來給咱們使用
select * from tab_array where array_contains(b,22);
//咱們查找b列中包含22字段的行。
那麼結果應該是後兩行
insert into table tab_array select array(oaddr,daddr), array(0) from tab_cdr;
//這句話主要是從其餘表中獲取數據而後插到咱們的表中,array(oaddr,daddr)那麼咱們的a字段是string,而後咱們選用了tab_cdr的兩個字段,而後tab_cdr裏面沒有int類型的,因此咱們就填0。
咱們查看一下:
select * from tab_cdr limit 10;
drop table tab_map;
create table tab_map(name string,info map<string,string>)
row format delimited fields terminated by ‘\t’
collection items terminated by ‘,’
map keys terminated by ‘:’;
那麼咱們有一個map.txt的文件爲:
Rob age:30,tel:4234323
Amy age:22,tel:43243
Bob age:33,tel:432434,addr:shanghai
接着:
load data local inpath ‘/home/robby/map.txt’ into table tab_map;
那麼咱們怎麼訪問map的字段呢?
select info[‘age’] from tab_map;
咱們如何從其它表中讀取數據到map表中?
insert into table tab_map select oaddr,map(‘oareacode’,oareacode,’daddr’,daddr) from tab_cdr;
結論:map裏面是能夠填任意多個的,無論你當時定義的幾個
drop table tab_st;
create table tab_st(name string,info struct<age:int,tel:string,addr:string>)
row format delimited fields terminated by ‘\t’
collection items terminated by ‘,’;
那麼咱們有準備好了的struts.txt數據爲:
Rob 30,432423
Amy 17,432423,beijing
Bob 28,213243,shanghai
而後加載數據:
load data local inpath ‘/home/robby/struts.txt’ into table tab_st;
那麼咱們怎麼訪問struct裏面的數據:
select info.age from tab_st;
insert into table tab_st select oaddr,name_struct(‘age’,0,’tel’,daddr,’addr’,dareacode) from tab_cdr;
結論:跟map不同,當時strust內定義了幾個就得插入幾個,固然了沒有的能夠爲null;
四中文件類型:
SEQUENCEFILE :壓縮後能夠進行mapreduce任務計算的
TEXTFILE:普通的文件
RCFILE:facebook弄出來的,針對hive的,性能比SEQUENCEFILE 還要好
INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname:自定義的類型。
舉個例子:
咱們有一個a.txt的文件,裏面存了內容,而後咱們用gzip命令壓縮一下,而後產生一個叫
a.txt.gz的文件.
而後咱們在hive裏面建立表
drop table tab_name;
create table tab_name(id int,name string) row format delimited fields terminated by ‘,’;
建立好後:
load data local inpath ‘/home/robby/a.txt.gz’ into table tab_name;
接着咱們觀察一下:
在hive下輸入:
dfs -ls /user/hive/warehouse/tab_name;
咱們發現,他直接存儲了咱們的壓縮文件a.txt.gz;
那麼咱們直接能夠用sql語句訪問咱們的表(由於hive會作解壓的工做)
select * from tab_name;
咱們普通文件的壓縮後不能直接進行mapreduce任務。這個很差的地方。
因此咱們不能用壓縮的文本文件作爲hive的存儲。同時呢咱們最好也不要用文本文件做爲文件的存儲,由於它佔的地方大。
所以呢,咱們就引出了上面的兩種格式
(blog.cdsn.net/wh62592855/atricle/details/6409680)
一種是:SEQUENCEFILE ,SEQUENCEFILE跟普通的文本文件的壓縮的區別是,普通的文本文件的壓縮是針對整個文件的壓縮,SEQUENCEFILE針對的是每一部分的壓縮。那麼是按行來分的。
一種是:RCFILE,那麼RCFILE也是針對每一部分的壓縮,那麼是按行分和按列分的混合體,先水平,再垂直。(通常咱們用的壓縮算法是LOZO)
1, sudo apt-get install liblzo2-dev
2, sudo apt-get install lzop
3, https://github.com/kevinweil/hadoop-lzo
a, git clone https://github.com/kevinweil/hadoop-lzo (不會能夠不 用這種)
b, download *.tar.gz
4, 修改 build.xml
搜索javah
加上<classpath refid="classpath"/>
<javah classpath="${build.classes}"
destdir="${build.native}/src/com/hadoop/compression/lzo"
force="yes"
verbose="yes">
<class name="com.hadoop.compression.lzo.LzoCompressor" />
<class name="com.hadoop.compression.lzo.LzoDecompressor" />
<classpath refid="classpath"/>
</javah>
5, export CFLAGS=-m32
export CXXFLAGS=-m32
ant compile-native tar
6, 拷貝 build/hadoop-lzo-0.4.15.jar 到 $HADOOP_HOME/lib
7, 修改core-site.xm
<property>
<name>io.compression.codecs</name>
<value>
org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.GzipCodec,org. apache.hadoop.io.compress.BZip2Codec,com.hadoop.compression.lzo.LzopCodec
</value>
</property>
<property>
<name>io.compression.codec.lzo.class</name>
<value>com.hadoop.compression.lzo.LzoCodec</value>
</property>
8, cp build/native/Linux-i386-32/lib/libgplcompression.so $HADOOP_HOME/lib/native/Linux-i386-32/
而後重啓hadoop就能夠了。
接着,咱們舉例看上面講的幾個文件類型是怎麼使用的,首先要準備數據
那麼數據咱們仍是用話單例子的數據。
1:首先咱們建立一個普通文本文件類型存儲的表
drop table tab_cdr;
create table tab_cdr(oaddr string,oareacode string,daddr string,dareacode string,ts string,type string) row format delimited fields teminated by ‘,’;
load data local inpath ‘/var/www/hadoop/test/output/b.txt’ into table tab_cdr;(加進去了二十萬條數據)
固然了,咱們能夠觀察一下:
hive> dfs -ls /user/hive/warehouse/tab_cdr/
那麼咱們看到大小爲9800000
2:咱們用SEQUENCEFILE來存儲
首先咱們設置一下參數:
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.copression.type=BLOCK://壓縮的方式有三種,按份壓縮,按行壓縮,按block壓縮
set mapred.output.compression.codec=org.apache.hadoop.io.compress.LzoCodec;
drop table tab_cdr_seq;
create table tab_cdr_seq(oaddr string,oareacode string,daddr string,dareacode string,ts string,type string) row format delimited fields teminated by ‘,’ stored as sequencefile;
insert overwrite table tab_cdr_seq select * from tab_cdr;(會啓mapreduce任務的)
用了overwrite會把原來的數據線清空。
而後咱們觀察:
hive> dfs -ls /user/hive/warehouse/tab_cdr_seq/
咱們看到這個文件的大小變爲:4379300
固然了這樣的壓縮比沒有咱們直接壓縮文本好,可是好處就是咱們能直接對壓縮後的文件進行mapreduce任務。
3:怎樣使用RCFILE:
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.copression.type=BLOCK:
set mapred.output.compression.codec=org.apache.hadoop.io.compress.LzoCodec;
drop table tab_cdr_rc;
create table tab_cdr_rc(oaddr string,oareacode string,daddr string,dareacode string,ts string,type string) row format delimited fields teminated by ‘,’ stored as rcfile;
insert overwrite table tab_cdr_rc select * from tab_cdr;(會啓mapreduce任務的)
那麼這個跟咱們的上面那個是很是像的。
觀察:
hive> dfs -ls /user/hive/warehouse/tab_cdr_rc/
咱們看到文件的大小爲:3605100
若是從壓縮比上看的話,sequencefile的差異不會太大,可是執行mapreduce的話,從整體上看,rcfile的要好一些,因此若是項目開發的話,咱們應該能夠優先使用rcfile。
此外:好比咱們寫這樣的語句
Select oaddr from tab_cdr where ofd=’xxxx’時
就是說咱們有這樣的語句只是查到部分字段的,那麼咱們若是用的是rcfile存儲的話,咱們這個語句的mapreduce會跳過不相關的列,這樣的話咱們的效率很高。
舉例:固然了這個例子跟咱們話單的業務表示聯合起來的,咱們當時話單業務的表裏面,也有歸屬地這一欄,可是當時咱們只是顯示了010等之類的數字,並無對應起來。
drop table tab_areaname;
create table tab_areaname(areacode string,cityname string)
row format delimited fields terminated by ',';
準備文件/usr/local/areaname.txt內容爲:
010,beijing
021,shanghai
020,guangzhou
加載數據:
load data local inpath '/usr/local/areaname.txt' overwrite into table tab_areaname;
而後咱們建立一個表,這個表的目的是用來存查詢獲得的結果的。
drop table tab_res1;
create table tab_res1(oaddr string,cityname string);
那麼咱們開始來作這個操做:
insert overwrite table tab_res1
select b.oaddr , a.cityname from tab_areaname a
join tab_cdr b
on a.areacode=b.oarecode;
//上面一共是一條語句,注意的是,咱們作連表查詢的時候,咱們把數據量小的那張表寫到join的左邊,這樣是爲了效率好(緣由是在作mapreduce的時候,在reduce階段hive會把join左邊的表加載到咱們的內存中)
接下來我們能夠查找一下:
select * from tab_res1 limit 100;
固然了也能夠看每一個城市有多少個話單
select cityname,count(*) from tab_res1 group by cityname;
insert overwrite table tab_res1
select /*+ MAPJOIN*/ b.oaddr , a.cityname from tab_areaname a
join tab_cdr b
on a.areacode=b.oarecode;
那麼顧名思義,咱們作這個連表是在map任務的時候就連了,沒有通過reduce的計算;
這樣的話,效率會高一些,固然了會有使用的限制的,得某一張表的數據量要小。
drop table tab_user;
create table tab_user(addr string);
insert overwrite table tab_user select distinct(oaddr) from tab_cdr limit 100;
//插入的數據是從tab_cdr裏面選擇的不重複的100個主機號碼
insert overwrite table tab_res1
select b.oaddr , a.cityname from tab_areaname a
join tab_cdr b
on a.areacode=b.oarecode
join tab_user c
on b.oaddr=c.addr;
比較這兩句的話,後面這句的效率更高一些
咱們作怎樣的操做?好比咱們想查詢tab_cdr裏面的一些字段,可是我不想操做全部的
我只是想查找部分用戶的,而這部分用戶保存在tab_user裏面,那麼咱們要像後面那樣寫。
select oaddr,oareacode from tab_cdr a join tab_user b on a.oaddr=b.addr;
select oaddr,oareacode from tab_cdr a left semi join tab_user b on a.oaddr=b.addr;