Hive 编程之DDL、DML、UDF、Select总结

  Hive的基本理论与安装可参看做者上一篇博文《Apache Hive 基本理论与安装指南》。html

1、Hive命令行

  全部的hive命令均可以经过hive命令行去执行,hive命令行中仍有许多选项。使用$hive -H查看:java

  -e 选项后面能够直接接一个hql语句,不用进入到hive命令行用户接口再输入hql语句。sql

  -f 选项后面接一个hql语句的文件。shell

  -i 选项在hql语句执行以前的初始化hql文件。例如添加、导入等操做均可以写在这个hql语句文件中。数据库

  在hive使用中,大可能是写不少脚本,在hive命令行中输入是属于交互式的,这就必须有工做人员在工做,不适合作批量处理。可使用-f或-i选项,一次性执行能够将全部的hql语句放在一个hql脚本文件中。例如:apache

$ mkdir -p /opt/shell/sql
$ vim /opt/shell/sql/test.sql
select * from table_name limit 5;
select * from table_name where professional="student";
select count(*) from table_name;
select count(*) from table_name group by professional;
select * from table_name where professional="student" order by age;

  将脚本保存退出后,再批量执行:json

$ hive -f /opt/shell/sql/test.sql

2、Hive DDL(Data Definition Language)

  详见官方文档。重点在于建立表和建立函数。vim

1. 建表语法

  • 建表语句

  从官方文档的Create Table中能够查看hive建表的命令,以下:数组

CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name    -- (Note: TEMPORARY available in Hive 0.14.0 and later)
  [(col_name data_type [COMMENT col_comment], ... [constraint_specification])]
  [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]
  [SKEWED BY (col_name, col_name, ...)                  -- (Note: Available in Hive 0.10.0 and later)]
     ON ((col_value, col_value, ...), (col_value, col_value, ...), ...)
     [STORED AS DIRECTORIES]
  [
   [ROW FORMAT row_format] 
   [STORED AS file_format]
     | STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]  -- (Note: Available in Hive 0.6.0 and later)
  ]
  [LOCATION hdfs_path]
  [TBLPROPERTIES (property_name=property_value, ...)]   -- (Note: Available in Hive 0.6.0 and later)
  [AS select_statement];   -- (Note: Available in Hive 0.5.0 and later; not supported for external tables)
 
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
  LIKE existing_table_or_view_name
  [LOCATION hdfs_path];
  • 数据类型
data_type
  : primitive_type
  | array_type
  | map_type
  | struct_type
  | union_type  -- (Note: Available in Hive 0.7.0 and later)

  data_type,有两种类型:一种是复杂类型,例如array_type(ARRAY < data_type >)、map_type(MAP < primitive_type, data_type >)、struct_type(STRUCT < col_name : data_type [COMMENT col_comment], ...>)、union_type(UNIONTYPE < data_type, data_type, ... >);简单类型有SMALLINT(占2个字节的整数)、INT(占4个字节的整数)、BIGINT(占8个字节的整数)、BOOLEAN、FLOAT、DOUBLE、STRING、BINARY、TIMESTAMP、DECIMAL、DATE、VARCHAR(0.12以后)、CHAR(字符,0.13以后)。浏览器

primitive_type
  : TINYINT
  | SMALLINT
  | INT
  | BIGINT
  | BOOLEAN
  | FLOAT
  | DOUBLE
  | DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later)
  | STRING
  | BINARY      -- (Note: Available in Hive 0.8.0 and later)
  | TIMESTAMP   -- (Note: Available in Hive 0.8.0 and later)
  | DECIMAL     -- (Note: Available in Hive 0.11.0 and later)
  | DECIMAL(precision, scale)  -- (Note: Available in Hive 0.13.0 and later)
  | DATE        -- (Note: Available in Hive 0.12.0 and later)
  | VARCHAR     -- (Note: Available in Hive 0.12.0 and later)
  | CHAR        -- (Note: Available in Hive 0.13.0 and later)
  • row_format
row_format
  : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
        [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
        [NULL DEFINED AS char]   -- (Note: Available in Hive 0.13 and later)
  | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]

  row_format:须要指出每一行是由什么隔开,而且要指出每一行中的每个字段是用什么隔开的。

  对于字段的隔开,复杂数据类型和简单数据类型不同。例如数组类型是复杂类型,其隔开符[COLLECTION ITEMS TERMINATED BY char],Map类型的要使用[MAP KEYS TERMINATED BY char]。[LINES TERMINATED BY char]能够设置行隔开符,若是不写,默认为回车换行。

  • file_format
file_format:
  : SEQUENCEFILE
  | TEXTFILE    -- (Default, depending on hive.default.fileformat configuration)
  | RCFILE      -- (Note: Available in Hive 0.6.0 and later)
  | ORC         -- (Note: Available in Hive 0.11.0 and later)
  | PARQUET     -- (Note: Available in Hive 0.13.0 and later)
  | AVRO        -- (Note: Available in Hive 0.14.0 and later)
  | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname

  SEQUENCEFILE表示序列压缩格式,以及RCFILE、ORC、PARQUET、AVRO都是压缩格式。TEXTFILE是默认的格式,文本格式。

2. 建立表案例一  

  • 查看数据

  为举例说明,这里先生成数据文件:

vim /root/person.txt
1,zhangsan,31,books-sports-math,city:shanghai-street:lujiazui-zipcode:313100
2,lisi,35,books-music,city:hangzhou-street:xihu-zipcode:222100
3,wangwu,25,computer-games,city:guangzhou-street:baiyun-zipcode:212300
  • 建立表

  根据数据建立一我的类表,包含人的编号、姓名、年龄、爱好、地址五个字段。

vim /opt/shell/sql/t_person.sql
create table t_person
(
    id int,
    name string,
    age int,
    likes array<string>,
    address map<string,string>
) row format delimited 
fields terminated by ',' 
collection items terminated by '-'
map keys terminated by ':' 
lines terminated by '\n' 
stored as textfile;

  根据表结构,字段之间按,隔开;likes的类型是array,因此能够有多个爱好,元素之间按-隔开,以,做为数组的结束;地址是map类型,也是collection类型, key和value按:隔开,每对key和value之间用-隔开(和collection一致);回车表明换行符。

  执行建立表脚本:

$ hive -f /opt/shell/sql/t_person.sql
  • 将数据从本地导入到hive
hive> load data local inpath '/root/person.txt' into table t_person;
  • 查看数据

 

3. 建立表案例二(分区表)

  当咱们要在关系型数据库中查找某一数据时,通常须要匹配数据库中的全部数据,因此能够经过分区来提升查询效率。把经常使用的查询条件做为一种分区,例如要查某一天的数据,事实上就是能够只匹配当天的数据,其余数据不匹配。下面以建一个日志管理表为例:

  • 数据文件

  文件常常按照天、小时等进行分割。故在此建立多个文件以下:

vim /root/log_2016-03-11.txt
111,1,200,2016-03-11
135,4,100,2016-03-11
211,3,300,2016-03-11
141,1,200,2016-03-11
131,2,400,2016-03-11
vim /root/log_2016-03-12.txt
121,2,300,2016-03-12
125,3,400,2016-03-12
211,1,400,2016-03-12
161,3,100,2016-03-12
171,5,200,2016-03-12
  • 建立表结构
create table t_log (id string,type int,pid string,logtime string)
partitioned by (day string)
row format delimited 
fields terminated by ','
stored as textfile;

  这里指定了按照天作分区。

  • 装载数据
hive> load data local inpath '/root/log_2016-03-11.txt' into table t_log partition (day='2016-03-11');
hive> load data local inpath '/root/log_2016-03-12.txt' into table t_log partition (day='2016-03-12');
  • 查看数据
hive> select * from t_log;

  从上图能够看出,数据增长了一个字段,左边是logtime,右边是分区day。因此,添加一个分区能够理解为添加一个字段;可是又不一样于添加一个字段,由于查询按照分区作限定(查询分区day='2016-03-11')时其余分区的数据不读取,而若是是字段的话,须要每一条数据进行匹配过滤。也能够从浏览器看出建立分区表的目录结构以下:

  建立分区,就会为每个分区建一个目录,因此在查询时,只在限定的分区目录里查询。

  查看某一天的数据量

hive> select count(*) from t_log where day='2016-03-11';

  查看某一个月的数据量

hive>select count(*) from t_log where day between 'xxx' and 'xxx';

  固然,这里须要先转换格式,略。

3、Hive DML(Data Manipulation Language)

  详见官方文档。DML是对数据进行增删改的脚本。可是数据在hdfs中,实际上不提供修改,只提供追加(insert),支持删除。

1. Loading files into tables

  • 语法

  load file将数据导入到表中。其语法为:

hive> LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

  local:若是导入的数据在Linux主机本地,就要添加[local],若是数据已经在hdfs上就不能加local;overwrite:覆盖;partition:若是表有分区就要加partition。

  • 实例
    • 将hdfs中的数据装载到hive  

  首先,上传Linux文件到hdfs

$ hdfs dfs -put /root/log_2016-03-1* /usr/input

  其次,在hive中执行导入

hive>load data inpath '/usr/input/log_2016-03-12.txt' into table t_log partition (day='2016-03-12');

hive>load data inpath '/usr/input/log_2016-03-12.txt' overwrite into table t_log partition (day='2016-03-12');

  注意:导入的分区要存在,导入到hive表后原来hdfs路径下的文件就不复存在了,即存在hdfs的目录变了,实际就是元数据变了,block的位置没有变。若是使用overwrite,则原来该表中指定分区的数据将所有清空,而后上传该文件。若是load相同文件名名到表中时,会默认生成副本filename_copy_1。文件中的数据格式要和表的结构相吻合。

    • 将Linux本地的数据装载到hive
hive>load data local inpath '/root/log_2016-03-11.txt' into table t_log partition (day='2016-03-11');

2. Inserting data into hive tables from queries

  • 语法
hive> INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
hive> INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;

  其中的select_statement1 FROM from_statement;是一个sql语句。这是用于查询hive中已经存在的数据,将查询结果给到一张新表中。

hive> INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...] 

  这个语句是和关系型数据库的insert语句用法是同样的。区别有三:一是,有partition;二是,能够一次插入多条数据;三是,这种语句是转成MapReduce去执行的。

  由于hive是一个工具,其做用是查询和统计hdfs上的数据的,对于查询结果通常就在控制台上显示,因此这个insert语句做用就是将查询的结果保存下来,用于后期的展现。

  • 实例
hive> insert into table t_log partition (day='2016-03-13’) values ('888',2,'100','2016-03-13’); 

  这个会启动MapReduce,由于数据在文件中不存在,要插到文件中至关于上传,会生成一个新的文件。这个不经常使用。因此实际上inset into语句的实际意义在于将查询结果放到新的表中。

3. Delete

  删除数据通常能够不在hive中删除,直接在hdfs上删除文件。由于删数据实际上就是删除文件。例如要删除以前插入到hive的t_log表day=2016-03-11分区下的log_2016-03-11.txt,能够执行以下命令:

#hdfs dfs -rm /user/hive/warehouse/t_log/day=2016-03-11/t_log-2016-03-11.txt

4、Hive UDF(Operators and User-Defined functions)

  详见官方文档

1. 内置运算符

  • 关系运算符

  见文档

  • 算术运算符

  见文档

  • 逻辑运算符

  见文档

  • 复杂类型构造函数(Complex Type Constructors)
    • 复杂类型函数或对象的构建

  【1】map(构造map对象)

  Creates a map with the given key/value pairs. (key1,value1,key2,value2,…)

  【2】struct(建立架构数组)

  Creates a struct with the given field values. (val1,val2,val3,…)。Struct的属性名和列名相对应。struct能够认为是面向对象的对象类型,是一个构造体,里面能够定义属性的值,field的名称是预先定义的,就像Java类的属性预先定义好了。

  【3】named_struct

  Creates a struct with the given field names and values. (name1,val1,name2,val2, …)。根据给定的Struct的属性名来建立构建数组

  【4】array(建立数组对象)

  Creates an array with the given elements. (val1,val2,val3,…)。把各(若干)个字段的值变成一个array。

  【5】create_union

  Creates a union type with value that is being pointes to by the tag parameter.

    • 复杂类型函数的运算符

  【1】A[n]

  A是array类型,n是int类型。A[n]表示数组A的第n+1个元素。

  【2】M[key]

  M是map类型,key是map集合中键的类型。M[key]是取map集合中键为key的值。注意使用是key须要使用单引号。

  【3】S.x

  S是struct类型,x表示struct中的某个属性。S.x,将会返回S这个struct中定义的x属性型中存储的值。

2. 内置函数

  • 数学函数

  • 集合操做函数

  • 类型转换函数

  • 日期函数

  • 条件/逻辑函数

   略。

  • 字符串函数

3. UDAF

  UDAF和UDF的区别在于传给函数的参数不同。UDF表示传给函数的参数只有一个值或一行值;UDAF是给函数传多个值或者多行值的函数,例如count(*),sum(col)等都是多行的值。

  UDAF(User- Defined Aggregation Funcation) 汇集函数,多进一出,例如count/max/min等。

4. UDTF

  详见文档。

5. UDF

  HivePlugins,Creating Custom UDFs。自定义函数须要如下几个步骤:首先要自定义一个类,继承UDF;其次,打成jar包;第三,将jar包加载到hive的classpath;第四,建立自定义函数;第五,使用函数。

  例如,要建立一个将字符串转成日期的函数。

  • 自定义类
package com.huidoo.hive;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.serde2.io.TimestampWritable;
import org.apache.hadoop.io.Text;

public class StringToDate extends UDF {
    /**
     * 定义evaluate方法。返回值类型定义为TimestampWritable
     * @param str
     * @param datefmt
     * @return
     * @throws Exception 
     */
    public TimestampWritable evaluate(final Text str,final Text datefmt) throws Exception{
        SimpleDateFormat sdf= new SimpleDateFormat(datefmt.toString()); //datefmt是传入的格式化字符串,须要建立SimpleDateFormat对象,Text类型要转成Java中的String类型。
        Date date= sdf.parse(str.toString()); //将字符串str,按照格式sdf转成java.util的Date类型
        TimestampWritable time=new TimestampWritable();//建立Hadoop的时间戳对象
        time.setTime(date.getTime());//将date转成Timestamp类型,而后使用Hadoop时间戳对象设置成相应的时间。
        return time;
    }
}
  • 打成jar包并上传到服务器

  略。std.jar

  • 将jar包加载到hive的classpath
hive> add jar /path/to/std.jar;
  •  建立函数

  语法:create 函数名(不能与内置的同样) as ‘自定义类的全限定名’;

hive> create function std as 'com.huidoo.hive.StringToDate';

  这就建立了一个函数,名为std。

  • 使用函数
hive> select std('2016-02-06 01:19:30','yyyy-MM-dd HH:mm:ss') from t_log limit 3;

5、Hive Select

1. 简单查询和使用/切换数据库

hive> select * from table_name;

  查看当前数据库:

hive> SELECT current_database();

  "db_name.table_name" allows a query to access tables in different databases.能够查询不一样数据库中的表。

  使用某数据库:

hive> USE database_name;

2. where从句

hive>SELECT * FROM sales WHERE amount > 10 AND region = "US"

3. ALL and DISTINCT从句

  使用distinct关键字去重查询,以下列出两个查询的区别:

hive> SELECT col1, col2 FROM t1

    1 3

    1 3

    1 4

    2 5

hive> SELECT DISTINCT col1, col2 FROM t1

    1 3

    1 4

    2 5

4. Join从句

  join用于表链接。两个表即两个文件能链接起来就必定有相同点,这就是说其中一个文件中某域的值和另外一个文件的某域的值相同,就能够链接。

hive> select col1,col2,col3 from t1 join t2 on+条件;

5. 基于Partition的查询

  这种查询语法就只要把partition当成一个字段便可。若是查询时要引入外键关联表也可使用JION…ON语句。

  • 非关联查询

  语法:

hive> select table_name.* from table_name where table_name.partition_name +条件;

  案例:

SELECT page_views.*
FROM page_views
WHERE page_views.date >= '2016-03-01' AND page_views.date <= '2016-03-31'
  • 关联查询

  语法:

hive> select table_name1.* from table_name1 join table_name2 on (table_name1.外键 = table_name2.主键 And table_name1.partiton_name +条件);

  案例:

SELECT page_views.*
FROM page_views JOIN dim_users 
ON (page_views.user_id = dim_users.id AND page_views.date >= '2016-03-01' AND page_views.date <= '2016-03-31');

6. Group by从句

hive> select col[list] from table_name group by col;

7. Order/Sort by从句

  sort by和order by的用法基本一致,都是作排序的,通常用order by。例如:

hive> select * from t_log order by id;

8. Having从句

  having从句必须依附于group by从句,在group从句后面接having从句,至关于增长一个条件。having后面能够接聚合函数,例如sum、avg等。

  • 单纯的group by语句
hive> select day from t_log group by day;

  其查询结果为:

  2016-03-11

  2016-03-12

  • 添加having从句
hive>select day from t_log group by day having avg(id)>150;

  其查询结果为:

  2016-03-12

  • hiving同效于子查询
hive> select day from (select day, avg(id) as avgid from t_log group by day) table2 where table2.avgid>150;

  这里将t_log表经过select day, avg(id) as avgid from t_log group by day查询获得的结果做为表再查询的。和上述的hiving从句获得的结果同样。

9. Limit从句

  限定查询返回的行数。

hive> select * from t_log limit 5;
相关文章
相关标签/搜索