​《hive编程指南》之hive的数据类型,创建表,外部表,分区,文件类型,字段分割格式。...

hive编程指南》之hive的数据类型,创建表,外部表,分区,文件类型,字段分割格式。

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

  [(col_name data_type [COMMENT col_comment], ...)]

  [COMMENT table_comment]

  [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]

  [ROW FORMAT row_format]

  [STORED AS file_format]

  [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;

 

 

 

 

 

 

 

 

 

 

 


转载于:https://my.oschina.net/u/1464779/blog/210708

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值