《hive編程指南》之hive的數據類型,建立表,外部表,分區,文件類型,字段分割格式。

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

這個是我從hivedocs裏面複製出來的,由於我感受我怎麼寫也沒人家寫得好。我最多無非就是在下面舉幾個例子,說明一下使用的方法。

在任意的地方寫好比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_nameput咱們的文件,咱們執行

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,....>

那麼接着咱們看array怎麼使用:

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;

接下來咱們看看map是這樣使用的

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裏面是能夠填任意多個的,無論你當時定義的幾個

接下來咱們看看struct是怎麼使用?(我的感受用的多)

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:普通的文件

RCFILEfacebook弄出來的,針對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)

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會跳過不相關的列,這樣的話咱們的效率很高。

join

舉例:固然了這個例子跟咱們話單的業務表示聯合起來的,咱們當時話單業務的表裏面,也有歸屬地這一欄,可是當時咱們只是顯示了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;

map join

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;

相關文章
相關標籤/搜索