Apache Hive 基本语法

Apache Hive 基本语法

    • 前言
    • 一、数据库
      • 1、创建数据库
      • 2、查看数据库
      • 3、使用数据库
      • 4、删除数据库
    • 二、数据库表
      • 1、创建表
        • A、创建内部表
        • B、创建外部表
        • C、创建分区表
        • D、创建分桶表
      • 2、修改表
        • A、修改普通表
        • B、修改分区表
        • 3、删除表
    • 三、其他操作
      • 1、load
      • 2、insert
        • A、多重插入
        • B、动态分区插入
      • 3、select
      • 4、Hive join
      • 5、UDF(user-defined function)
      • 6、hive的分隔符

前言

这篇文档是我两年前刚学习Hive的时候写的相当于笔记一样的东西,无意中被我翻出来了。。。

一、数据库

1、创建数据库

create database|schema [if not exists] xiaoming;

中括号中的if not exists表示如果数据库已经存在就不创建,不存在则创建。

2、查看数据库

show databases|schemas;

3、使用数据库

use xiaoming;

4、删除数据库

drop database [if exists] xiaoming [restrict|cascade];

删除数据库,默认情况下,hive不允许删除含有表的数据库,要先将数据库中的表清空才能drop,否则会报错,可以在语句后面cascade关键字,强制删除一个数据库,默认是restrict,表示有限制的

二、数据库表

1、创建表

A、创建内部表

create table [if not exists] xiaoming01(id int,name string);

此时创建的表没有手动指定分隔符,所以采用hive默认的分隔符/001。

加载数据:

load data [local] inpath 'path' [overwrite] into table xiaoming01;

B、创建外部表

create external table [if not exists] xiaoming01(id int,name string1) location 'path';

外部表和内部表的区别:Hive在创建内部表的时候,会将映射为表的数据移动到数据仓库指定的路径下,而创建外部表不会,创建外部表hive只会记录数据所在的路径,不会对数据的位置做任何改变。再删除表的时候,内部表会将元数据和数据一起删除,外部表只会删除元数据,不会删除数据。

装载数据:(此处的path需和创建表的时候的location指点的路径一致)

load data [local] inpath 'path' into table xiaoming01;

C、创建分区表

分区建表分为2种,一种是单分区,也就是说在表文件夹目录下只有一级文件夹目录。另外一种是多分区,表文件夹下出现多文件夹嵌套模式。

create table xiaoming01(id int,name string) partitioned by(country string);

以上是创建单分区表,以国家为分区字段,注意分区字段一定不能是表中已经存在的字段。

create table xiaoming01(id int,name string) partitioned by(country string,province string);

以上是创建双分区表,以国家为第一分区字段,省份为第二分区字段。

装载数据:

-- 单分区表:
load data [local] inpath 'path' [overwrite] into table xioaming01 partition(country='CN');
-- 双分区表:
load data [local] inpath 'paht' [overwrite] into table xioaming02 partition(country='CN',province='ShangHai');

查看分区表的分区:

show partitions xiaoming01;

基于分区的查询:

select * from xiaoming01 where country = 'CN'; -- 查询CN分区下的数据

desc xiaoming01; -- 查询表结构

注意:

  1. 分区表是一个虚拟的字段,不存放任何数据。
  2. 分区字段的数据是在装载分区表数据是时候指定的
  3. 分区表的目的是为了减少查询查询数据时进行全表扫描的成本,提高查询效率。

D、创建分桶表

首先,hive在默认情况下是不支持分桶操作的,需要我们手动开启。

set hive.enforce.bucketing = true; -- 开启分桶表

set mapreduce.job.reduces = 4; -- 设置reduce的个数为4,也是最大分桶的个数

create table xiaoming01(id int,name string) clustered by(id) into 4 buckets; -- 创建一个分桶表分桶字段为id,指定4个分桶。

装载数据:(分桶表装载数据不能使用load的方式)

insert overwrite table xiaoming01 select * from student cluster by(id);

分桶表装载数据需要使用insert+select,需要使用一个中间临时表,进行分桶查询,再将查询到的结果插入到分桶表中。(分桶需要经过reduce这一过程,普通的load本质就是hive替我们做了put操作,没有经过MR程序)。

需求: 对某列进行分桶的同时,根据另一列进行排序

insert table xiaoming01 select * from student distribute by(id) sort by(name asc|desc);

在排序的时候不能使用cluster by 和 sort by 进行组合,因为cluster by默认是分桶且排序的,如果再进行排序就会冲突。

cluster by(分桶且排序,同一字段) == distribute by(分桶) + sort by(排序,字段可以不同)

注意:

  1. 分桶表(分簇表)创建的时候 分桶字段必须是表中已经存储(存在)的字段。
  2. 分桶表数据采用insert+select装载数据的时候进行了mr程序,插入的分桶数据来自对应的mr程序的partition中。所以默认是采用哈希分桶。
  3. 分桶表也是把表所映射的结构化数据文件分成更细致的数据,但是更多的是用在join查询上提高效率。

2、修改表

A、修改普通表

  • 查询重命名表为xiaoming01;
alter table xiaoming01 rename to xiaoming02;
  • 在xiaoming01表中增加了一列dept,字段类型为string;后面的comment是注释,可有可无。
alter table xiaoming01 add columns(dept string comment '部门');
  • 删除xiaoming01中的dept列;
alter table xiaoming01 drop[column] dept;
  • 查询更改xiaoming01中的name字段,更改为newName,并将字段类型改为string,可以更改字段的顺序;
alter table xiaoming01 change name newName string[first|after column_name];
  • 替换xiaoming01中的newName字段为name字段;
alter table xiaoming01 replace columns (newName string name string);

B、修改分区表

  • 增加分区
alter table xiaoming01 add partition (country='USA') location 'path';

​ 在执行添加分区时,path文件夹下的数据不会被移动。并且没有分区目录country=USA

  • 增加多个个分区
alter table xiaoming01 add partition(country='USA',province='NewYork') location 'path' partition(country='CN',province='ShangHai') location 'path';
  • 删除分区
alter table xiaoming01 drop if exists partition(country='USA');
  • 修改分区
alter table xiaoming01 partition(country='USA') rename to partition(country='CN');

3、删除表

truncate table xiaoming01; -- 删除xiaoming01表的所有数据。

drop table xiaoming01; -- 删除xiaoming01这张表。

三、其他操作

1、load

使用load装载数据时,Hive不会进行任何转换,加载操作是将数据文件移动到与 Hive 表对应的位置的纯复制/移动操作。

load data [local] inpath 'path' [overwrite] into table tablename [partition (partcol1=val1, partcol2=val2 ...)] ;

2、insert

Hive 可以使用 insert 子句将查询结果插入到表中

-- overwrite 关键字会将原本的数据进行覆盖
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;

-- into 关键字则是直接导入
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;

需要保证查询结果列的数目和需要插入数据表格的列数目一致。

如果查询出来的数据类型和插入表格对应的列数据类型不一致,将会进行转换, 但是不能保证转换一定成功,转换失败的数据将会为 NULL。

可以将一个表查询出来的数据插入到原表中, 结果就是相当于复制了一份 cite 表格中的数据。

A、多重插入

首先创建三张表,第一张表中的第一个字段和第二张表的字段想同,第二个字段和第三张表的字段相同

create table source_table (id int, name string) row format delimited fields terminated by ',';

create table test_insert1 (id int) row format delimited fields terminated by ',';

create table test_insert2 (name string) row format delimited fields terminated by ',';

下面这条的语句的也是就是从source_table中查询出来id插入到test_insert1表中,将name查询出来插入到test_insert2表中,这样既完成了多重插入,将一个表中的字段分别插入到若干个表中。

from source_table -- 查询 source_table 表

insert overwrite table test_insert1

select id -- 将id字段插入 test_insert1 表中

insert overwrite table test_insert2

select name; -- 将name字段插入 test_insert2 表中

B、动态分区插入

动态分区功能和分桶功能一样都是默认关闭的,我们需要手动开启。

set hive.exec.dynamic.partition=true; -- 是否开启动态分区功能,默认false关闭。

set hive.exec.dynamic.partition.mode=nonstrict; -- 动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。

需求: 将dynamic_partition_table中的数据按照时间(day),插入到目标表d_p_t的相应分区中。

-- 创建源数据表
create table dynamic_partition_table(day string,ip string)row format delimited fields terminated by ","; 

load data local inpath 'path' into table dynamic_partition_table;
2015-05-10,ip1
2015-05-10,ip2
2015-06-14,ip3
2015-06-14,ip4
2015-06-15,ip1
2015-06-15,ip2
 
-- 创建导入目标表:
create table d_p_t(ip string) partitioned by (month string,day string);

-- 进行动态插入操作:
insert overwrite table d_p_t partition (month,day) 
select ip,substr(day,1,7) as month,day 
from dynamic_partition_table;

需求: 查询结果导出到文件系统

-- 将查询结果保存到指定的文件目录(可以是本地,也可以是hdfs)


-- 将t_p表的数据全部查出导入到本地文件中
insert overwrite local directory '/home/hadoop/test'
select * from t_p;

-- 将t_p表的数据全部查出导入到HDFS中
insert overwrite directory '/aaa/test'
select * from t_p;

注意:

多态插入的字段是按位置一一映射的,所以即使是字段名字不一样但是如果位置对应就会插入成功。

3、select

基本的 Select 语法结构

select [ all | distinct ] select_expr,select_expr,...from table_name join table_other on expr

[where where_condition]

[group by col_list [hiving condition] ]

[cluster by col_list | [distribute by col_list ]-[sort by | order by col_list] ]

[limit number]

以上语法的顺序不可变!

说明:

1、order by:会对输入做全局排序,因此只会有一个reduce task,当输入的数据量大时,会导致计算需要较长的时间。

2、sort by:不是全局排序,会在数据进入reduce task前排序完成,所以sort by只保证每个reduce的输出排序,不保证全局排序。

3、distribute by:是根据指定字段的数据将数据分到不同的reduce,分发算法是hash散列。

4、cluster by:除了具有distribute by的功能外,还会对数据指定的字段进行排序。如果分桶和 sort 字段是同一个时,此时,cluster by = distribute by + sort by。

5、distinct:表示从一个字段中获取不同的值。

4、Hive join

内连接:将符合两边连接条件的数据查询出来

select * from t_a a inner join t_b b on a.id=b.id;

左外连接:以左表数据为匹配标准,右边若匹配不上则数据显示null

select * from t_a a left join t_b b on a.id=b.id;

右外连接:与左外连接相反

select * from t_a a right join t_b b on a.id=b.id;

左半连接:左半连接会返回左边表的记录,前提是其记录对于右边表满足on语句中的判定条件。

select * from t_a a left semi join t_b b on a.id=b.id;

全连接(full outer join):返回左右两边所有的数据,匹配不到的先生为null。

select * from t_a a full join t_b b on a.id=b.id;

in/exists关键字(1.2.1之后新特性):效果等同于left semi join

select * from t_a a where a.id in (select id from t_b);
select * from t_a a where exists (select * from t_b b where a.id=b.id);

cross join(##慎用)返回两个表的笛卡尔积结果,不需要指定关联键。

select a.*,b.* from a cross join b;

注意:

  1. reduce在join时会缓存除了最后一个表的所有表的数据,因此,在开发中,我们应该把最大的表放在最后面,减小内存的缓存。
  2. hive支持等值join查询,不支持非等值查询,另外,hive支持2张表以上的join。
  3. join应该在在where语句前面。
  4. join是不能交换位置的,无论是left还是right join都是左连接的。

5、UDF(user-defined function)

当hive内置的函数无发满足我们的实际需求时,我们就可以考虑编写一个自定义函数了。

自定义函数类别 :

  • UDF:作用于单个数据行,产生一个数据行作为输出。(数学函数,字符串函数)

  • UDAF(用户定义聚集函数):接收多个输入数据行,并产生一个输出数据行。(count, max)

如何编写一个UDF程序:

  1. 编写java程序,继承UDF类,并重载evaluate方法。

    import org.apache.hadoop.hive.ql.exec.UDF;
    public class AddUdf extends UDF {
     public Integer evaluate(Integer a, Integer b) {
         if (null == a || null == b) {
         	return null;
         } 
         return a + b;
     }
     public Double evaluate(Double a, Double b) {
         if (a == null || b == null)
         	return null;
         return a + b;
         }
     }	
    
  2. 打成jar包上传到服务器

  3. 将jar包添加到hive add jar /path/AddUdf.jar;

  4. 创建临时函数与开发好的class关联起来

    create temporary function add_example as 'xxx.AddUdf';
    
  5. 使用自定义函数 SELECT add_example(scores.math, scores.art) FROM scores;

    --销毁临时函数
    drop temporary function add_example
    

6、hive的分隔符

A、hive的读文件机制:首先调用inputformat(默认为TextInputFormat)去读取数据,一行一行的读入,然后使用SerDe(默认LazySimpleSerDe)的 Deserializer,将一条记录切分为各个字段(默认分隔符\001

所以,hive的默认分隔符是\001,所以如果我们没有指定分隔符的时候,我们load的文件中的分隔符也需要是\001,否则程序虽然不会报错,但会识别不出数据,返回null,null,null。。。

B、Hive 对文件中字段的分隔符默认情况下只支持单字节分隔符,如果数据文件中的分隔符是多字符的,如下所示: 01||zhangsan 02||lisi 可用使用 RegexSerDe 通过正则表达式来抽取字段 。

create table t_bi_reg(id string,name string) 
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe' 
with serdeproperties( 
'input.regex'='(.*)\\|\\|(.*)', 
'output.format.string'='%1$s %2$s' 
) 
stored as textfile; 

其中: input.regex:输入的正则表达式表示 || 左右两边任意字符被抽取为一个字段 output.format.string:输出的正则表达式%1 s s %2 ss 则分别表示表中的第一个字段、第二个地段

注意事项:

a、使用 RegexSerDe 类时,所有的字段必须为 string

b、input.regex 里面,以一个匹配组,表示一个字段

你可能感兴趣的:(BigData,Hive)