Hive基本语法操练

Posted 学而不思则罔,思而不学则殆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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]

CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXIST 选项来忽略这个异常

EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)

LIKE 允许用户复制现有的表结构,但是不复制数据

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

用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表的具体的列的数据。

•STORED AS

SEQUENCEFILE

| TEXTFILE

| RCFILE

| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname

如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCE

例:创建外部表

hive> CREATE EXTERNAL TABLE IF NOT EXISTS student2
    > (sno INT,sname STRING,age INT,sex STRING)   
    > ROW FORMAT DELIMITED                        
    > FIELDS TERMINATED BY \'\\t\'                   
    > STORED AS TEXTFILE                          
    > LOCATION \'/user/external\';      

 

一些基本操作:

删除:
 hive> DROP TABLE test1;

修改表结构:
 DESC student1;
hive> ALTER TABLE student1 ADD COLUMNS  
    > (address STRING,grade STRING);

修改表名:
hive> ALTER TABLE student1 RENAME TO student3;

创建和已知表相同结构的表:
hive> CREATE TABLE copy_student1 LIKE student1;

导入外部文件数据:
加载数据到student1表中
LOAD DATA LOCAL INPATH \'/home/hadoop/data/student1.txt\' INTO TABLE student1;

加载hdfs中的文件:
LOAD DATA INPATH \'/user/hive/student1.txt\' INTO TABLE copy_student1;

复制表数据:
 INSERT OVERWRITE TABLE copy_student2 SELECT * FROM student1;

多表同时复制:
hive> FROM student1                                       
    > INSERT OVERWRITE TABLE copy_student3
    > SELECT *                            
    > INSERT OVERWRITE TABLE copy_student4
    > SELECT *;

 

ORDER BY 会对输入做全局排序,因此只有一个 Reduce(多个 Reduce 无法保证全局有序)会导致当输入规模较大时,需要较长的计算时间。使用 ORDER BY 查询的时候,为了优化查询的速度,使用 hive.mapred.mode 属性。

hive.mapred.mode = nonstrict;(default value/默认值)
hive.mapred.mode=strict;

与数据库中 ORDER BY 的区别在于,在 hive.mapred.mode=strict 模式下必须指定limit ,否则执行会报错。

hive> set hive.mapred.mode=strict;
hive> select * from group_test order by uid limit 5;

 

sort by 不受 hive.mapred.mode 的值是否为 strict 和 nostrict 的影响。sort by 的数据只能保证在同一个 Reduce 中的数据可以按指定字段排序。

使用 sort by 可以指定执行的 Reduce 个数(set mapred.reduce.tasks=< number>)这样可以输出更多的数据。对输出的数据再执行归并排序,即可以得到全部结果。

hive> set hive.mapred.mode=strict;
hive> select * from group_test sort by uid ;

 

DISTRIBUTE BY 排序查询

-- 按照指定的字段对数据划分到不同的输出 Reduce 文件中,操作如下。
hive> insert overwrite local directory \'/home/hadoop/djt/test\' select * from group_test distribute by length(gender);

--此方法根据 gender 的长度划分到不同的 Reduce 中,最终输出到不同的文件中。length 是内建函数,也可以指定其它的函数或者使用自定义函数。
hive> insert overwrite local directory \'/home/hadoop/djt/test\' select * from group_test order by gender  distribute by length(gender);
order by gender 与 distribute by length(gender) 不能共用。

 

 

索引操作

创建一个索引

hive> create index user_index on table user(id) 
    > as \'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler\' 
    > with deferred rebuild
    > IN TABLE user_index_table;
hive> alter index user_index on user rebuild;
hive> select * from user_index_table limit 5; 
0       hdfs://mycluster/user/hive/warehouse/table02/000000_0   [0]
1       hdfs://mycluster/user/hive/warehouse/table02/000000_0   [352]
2       hdfs://mycluster/user/hive/warehouse/table02/000000_0   [704]
3       hdfs://mycluster/user/hive/warehouse/table02/000000_0   [1056]
4       hdfs://mycluster/user/hive/warehouse/table02/000000_0   [1408]
Time taken: 0.244 seconds, Fetched: 5 row(s)

 

 

索引案例

创建一个索引测试表 index_test,dt作为分区属性,“ROW FORMAT DELIMITED FILEDS TERMINATED BY \',\'” 表示用逗号分割字符串,默认为‘\\001’。

 create table index_test(id INT,name STRING) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY \',\';

创建一个临时索引表 index_tmp。

hive> create table index_tmp(id INT,name STRING,dt STRING) ROW FORMAT DELIMITED FILEDS TERMINATED BY \',\';

加载本地数据到 index_tmp 表中。

hive> load data local inpath \'/home/hadoop/djt/test.txt\' into table index_tmp

设置 Hive 的索引属性来优化索引查询,命令如下。

hive> set hive.exec.dynamic.partition.mode=nonstrict;----设置所有列为 dynamic partition
hive> set hive.exec.dynamic.partition=true;----使用动态分区

查询index_tmp 表中的数据,插入 table_test 表中。

hive> insert overwrite table index_test partition(dt) select id,name,dt from index_tmp;
--使用 index_test 表,在属性 id 上创建一个索引 index1_index_test 。
hive> create index index1_index_test on table index_test(id) as \'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler\' WITH DEFERERD REBUILD;

--填充索引数据。
hive> alter index index1_index_test on index_test rebuild;

--查看创建的索引。
hive> show index on index_test

-- 查看分区信息。
hive> show partitions index_test;

 

修改配置文件信息:

< property>
    < name>hive.optimize.index.filter< /name>
    < value>true< /value>
< /property>
< property>
    < name>hive.optimize.index.groupby< /name>
    < value>true< /value>
< /property>
< property>
    < name>hive.optimize.index.filter.compact.minsize< /name>
    < value>5120< /value>
< /property>

hive.optimize.index.filterhive.optimize.index.groupby 参数默认是 false。使用索引的时候必须把这两个参数开启,才能起到作用。

hive.optimize.index.filter.compact.minsize 参数为输入一个紧凑的索引将被自动采用最小尺寸、默认5368709120(以字节为单位)。

 

分区操作

Hive 的分区通过在创建表时启动 PARTITION BY 实现,用来分区的维度并不是实际数据的某一列,具体分区的标志是由插入内容时给定的。当要查询某一分区的内容时可以采用 WHERE 语句, 例如使用 “WHERE tablename.partition_key>a” 创建含分区的表。创建分区语法如下。

CREATE TABLE table_name(
...
)
PARTITION BY (dt STRING,country STRING)

1、 创建分区

Hive 中创建分区表没有什么复杂的分区类型(范围分区、列表分区、hash 分区,混合分区等)。分区列也不是表中的一个实际的字段,而是一个或者多个伪列。意思是说,在表的数据文件中实际并不保存分区列的信息与数据。

创建一个简单的分区表。

hive> create table partition_test(member_id string,name string) partitioned by (stat_date string,province string) row format delimited fields terminated by \',\';

 

--这个例子中创建了 stat_date 和 province 两个字段作为分区列。通常情况下需要预先创建好分区,然后才能使用该分区。例如:
hive> alter table partition_test add partition (stat_date=\'2015-01-18\',province=\'beijing\');

--这样就创建了一个分区。这时会看到 Hive 在HDFS 存储中创建了一个相应的文件夹。
$ hadoop fs -ls /user/hive/warehouse/partition_test/stat_date=2015-01-18
/user/hive/warehouse/partition_test/stat_date=2015-01-18/province=beijing----显示刚刚创建的分区

每一个分区都会有一个独立的文件夹,在上面例子中,stat_date 是主层次,province 是 副层次。

 

--向分区表中插入数据
--使用一个辅助的非分区表 partition_test_input 准备向 partition_test 中插入数据,实现步骤如下。

insert overwrite table partition_test partition(stat_date=\'2015-01-18\',province=\'jiangsu\') select member_id,name from partition_test_input where stat_date=\'2015-01-18\' and province=\'jiangsu\';

向多个分区插入数据,命令如下。
hive> from partition_test_input
insert overwrite table partition_test partition(stat_date=\'2015-01-18\',province=\'jiangsu\') select member_id,name from partition_test_input where stat_date=\'2015-01-18\' and province=\'jiangsu\'
insert overwrite table partition_test partition(stat_date=\'2015-01-28\',province=\'sichuan\') select member_id,name from partition_test_input where stat_date=\'2015-01-28\' and province=\'sichuan\'
insert overwrite table partition_test partition(stat_date=\'2015-01-28\',province=\'beijing\') select member_id,name from partition_test_input where stat_date=\'2015-01-28\' and province=\'beijing\';

 

 动态分区的产生

按照上面的方法向分区表中插入数据,如果数据源很大,针对一个分区就要写一个 insert ,非常麻烦。使用动态分区可以很好地解决上述问题。动态分区可以根据查询得到的数据自动匹配到相应的分区中去。动态分区可以通过下面的设置来打开:

set hive.exec.dynamic.partition=true;  
set hive.exec.dynamic.partition.mode=nonstrict; 

动态分区的使用方法很简单,假设向 stat_date=\'2015-01-18\' 这个分区下插入数据,至于 province 插到哪个子分区下让数据库自己来判断。stat_date 叫做静态分区列,province 叫做动态分区列。

hive> insert overwrite table partition_test partition(stat_date=\'2015-01-18\',province)
select member_id,name province from partition_test_input where stat_date=\'2015-01-18\';

注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区。

 

几个常用参数

hive.exec.max.dynamic.partitions.pernode:每一个 MapReduce Job 允许创建的分区的最大数量,如果超过这个数量就会报错(默认值100)。

hive.exec.max.dynamic.partitions:一个 dml 语句允许创建的所有分区的最大数量(默认值100)。

hive.exec.max.created.files:所有 MapReduce Job 允许创建的文件的最大数量(默认值10000)。

尽量让分区列的值相同的数据在同一个 MapReduce 中,这样每一个 MapReduce 可以尽量少地产生新的文件夹,可以通过 DISTRIBUTE BY 将分区列值相同的数据放到一起,命令如下。

hive> insert overwrite table partition_test partition(stat_date,province)
select memeber_id,name,stat_date,province from partition_test_input distribute by stat_date,province;

 

桶操作

对于每一个表或者是分区,Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive是针对某一列进行分桶。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶中。分桶的好处是可以获得更高的查询处理效率。使取样更高效。
分桶其实就是把大表化成了“小表”,然后 Map-Side Join 解决之,这是用来解决大表与小表之间的连接问题。将桶中的数据按某列进行排序会提高查询效率。

BUCKET 主要作用如下。

1)数据 sampling;

2)提升某些查询操作效率,例如 Map-Side Join。

 

需要特别主要的是,CLUSTERED BY 和 SORT BY 不会影响数据的导入,这意味着,用户必须自己负责数据的导入,包括数据额分桶和排序。 \'set hive.enforce.bucketing=true\' 可以自动控制上一轮 Reduce 的数量从而适配 BUCKET 的个数,当然,用户也可以自主设置 mapred.reduce.tasks 去适配 BUCKET 个数,推荐使用:

hive> set hive.enforce.bucketing=true;
1) 创建临时表 student_tmp,并导入数据。
hive> desc student_tmp;
hive> select * from student_tmp;

2) 创建 student 表。
hive> create table student(id int,age int,name string)
partitioned by (stat_date string)
clustered by (id) sorted by(age) into 2 bucket
row format delimited fields terminated by \',\';

3) 设置环境变量。
hive> set hive.enforce.bucketing=true;

4) 插入数据。
hive> from student_tmp
insert overwrite table student partition(stat_date=\'2015-01-19\')
select id,age,name where stat_date=\'2015-01-18\' sort by age;

5) 查看文件目录。
$ hadoop fs -ls /usr/hive/warehouse/student/stat_date=2015-01-19/

6) 查看 sampling 数据。
hive> select * from student tablesample(bucket 1 out of 2 on id);
tablesample 是抽样语句,语法如下。

tablesample(bucket x out of y)

y 必须是 table 中 BUCKET 总数的倍数或者因子。

 

Hive 复合类型

 

hive提供了复合数据类型:

 

 1)Structs: structs内部的数据可以通过DOT(.)来存取。例如,表中一列c的类型为STRUCT{a INT; b INT},我们可以通过c.a来访问域a。

 

 2)Map(K-V对):访问指定域可以通过["指定域名称"]进行。例如,一个Map M包含了一个group-》gid的kv对,gid的值可以通过M[\'group\']来获取。

 

 3)Array:array中的数据为相同类型。例如,假如array A中元素[\'a\',\'b\',\'c\'],则A[1]的值为\'b\'

1、Struct使用

 1) 建表
hive> create table student_test(id INT, info struct< name:STRING, age:INT>)  
> ROW FORMAT DELIMITED FIELDS TERMINATED BY \',\'                         
> COLLECTION ITEMS TERMINATED BY \':\';
 \'FIELDS TERMINATED BY\' :字段与字段之间的分隔符。\'COLLECTION ITEMS TERMINATED BY\' :一个字段各个item的分隔符。

 2) 导入数据
$ cat test5.txt   
1,zhou:30  
2,yan:30  
3,chen:20  
4,li:80  
hive> LOAD DATA LOCAL INPATH \'/home/hadoop/djt/test5.txt\' INTO TABLE student_test;

 3) 查询数据
hive> select info.age from student_test;  

2、Array使用
 1) 建表
hive> create table class_test(name string, student_id_list array< INT>)  
> ROW FORMAT DELIMITED                                              
> FIELDS TERMINATED BY \',\'                                          
> COLLECTION ITEMS TERMINATED BY \':\';

 2) 导入数据
$ cat test6.txt   
034,1:2:3:4  
035,5:6  
036,7:8:9:10  
hive>  LOAD DATA LOCAL INPATH \'/home/work/data/test6.txt\' INTO TABLE class_test ; 

 3) 查询
hive> select student_id_list[3] from class_test; 

3、Map使用
 1) 建表
hive> create table employee(id string, perf map< string, int>)       
> ROW FORMAT DELIMITED                                          
> FIELDS TERMINATED BY \'\\t\'                                
> COLLECTION ITEMS TERMINATED BY \',\'                       
> MAP KEYS TERMINATED BY \':\';  
 ‘MAP KEYS TERMINATED BY’ :key value分隔符

 2) 导入数据
$ cat test7.txt   
1       job:80,team:60,person:70  
2       job:60,team:80  
3       job:90,team:70,person:100  
hive>  LOAD DATA LOCAL INPATH \'/home/work/data/test7.txt\' INTO TABLE employee;  

 3) 查询
hive> select perf[\'person\'] from employee;

 

 

Hive 的 JOIN 用法

 hive只支持等连接,外连接,左半连接。hive不支持非相等的join条件(通过其他方式实现,如left outer join),因为它很难在map/reduce job实现这样的条件。而且,hive可以join两个以上的表。

1、等连接

只有等连接才允许
hive> SELECT a.* FROM a JOIN b ON (a.id = b.id)  
hive> SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department) 

2、多表连接
 同个查询,可以join两个以上的表
hive> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 

3、join的缓存和任务转换
 hive转换多表join时,如果每个表在join字句中,使用的都是同一个列,只会转换为一个单独的map/reduce。
hive
> SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c 以上是关于Hive基本语法操练的主要内容,如果未能解决你的问题,请参考以下文章

Hive 基本语法操练:分区操作和桶操作

react.js基本操练

hive的基本语法

Hive中基本语法

hive的基本语法汇总(hql)

Hive--05---DML----查询基本语法