全栈工程师开发手册 (作者:栾鹏)
架构系列文章
Hive是一个基于Hadoop的数据仓库,最初由Facebook提供,使用HQL作为查询接口、HDFS作为存储底层、mapReduce作为执行层,设计目的是让SQL技能良好,但Java技能较弱的分析师可以查询海量数据,2008年facebook把Hive项目贡献给Apache。Hive提供了比较完整的SQL功能(本质是将SQL转换为MapReduce),自身最大的缺点就是执行速度慢。Hive有自身的元数据结构描述,可以使用MySql\ProstgreSql\oracle 等关系型数据库来进行存储,但请注意Hive中的所有数据都存储在HDFS中。虽然 hive 可能存在这样那样的问题,但它作为后续研究 sparkSql 的基础,值得重点研究。
Hive是典型C/S模式。Client端有JDBC/ODBC Client和Thrift Client两类。Server 端则分为如下几个部分:
[外链图片转存失败(img-q6Hh8lf2-1563870912808)(http://bbs.umeng.com/data/attachment/forum/201512/18/181155nphez3wbykbu4hud.jpg)]
用户接口:client
CLI(hive shell)、JDBC/ODBC(java访问hive),WEBUI(浏览器访问hive)
元数据:metastore
元数据包括:表名、表所属数据库、表的拥有者、列/分区字段、表的类型、表数据所在目录。
Hadoop
使用hdfs进程数据存储,运行在yarn上,使用mapreduce进行计算。
驱动器:dirver
包含:解析器、编译器、优化器、执行器
解析器:将SQL字符串转换成抽象语法树AST,这一步一般都是用第三方工具库完成,比如antlr;对AST语法树进行分析,比如表否存在、字段是否存在、SQL语义是否有误。
编译器:将AST编译生成逻辑执行计划。
优化器:对逻辑执行计划进行优化。
执行器:把逻辑执行计划转换成物理执行计划。对于hive来说,就是MR/TEZ/Spark;
1)操作接口使用SQL语法,提供快速开发的能力。
2)避免了去屑mapreduce,减少开发人员学习成本。
3)统一元数据管理,可与impala/spark等共享元数据。
4)因底层基于hadoop,易于扩展,支持自定义函数UDF。
5)数据离线处理,比如日志分析,海量数据结构化分析。
6)Hive执行延迟比较高,适合于做离线分析处理,不适合实时查询。
7)Hive优势在于处理大数据集,对于小数据集没有优势。
包含shell命令语法、HiveQl语法、访问方式等,如下图:
Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL 去查询分析需要的内容,这套SQL 简称Hive SQL,使不熟悉mapreduce 的用户很方便的利用SQL 语言查询,汇总,分析数据。而mapreduce开发人员可以把己写的mapper 和reducer 作为插件来支持Hive 做更复杂的数据分析。
它与关系型数据库的SQL 略有不同,但支持了绝大多数的语句如DDL、DML 以及常见的聚合函数、连接查询、条件查询。HIVE不适合用于联机,也不提供实时查询功能。它最适合应用在基于大量不可变数据的批处理作业。
HIVE的特点:可伸缩(在Hadoop的集群上动态的添加设备),可扩展,容错,输入格式的松散耦合。
Hive 的官方文档中对查询语言有了很详细的描述,请参考:http://wiki.apache.org/hadoop/Hive/LanguageManual ,本文的内容大部分翻译自该页面,期间加入了一些在使用过程中需要注意到的事项。
建表:
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]
[sorted as file_format]
[location hdfs_path]
例如:
CREATE TABLE page_view(
viewTime INT,
userid BIGINT,
page_url STRING,
referrer_url STRING,
ip STRING COMMENT 'IP Address of the User')
COMMENT 'This is the page view table'
PARTITIONED BY(dt STRING, country STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
STORED AS TEXTFILE;
create table创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用if not exists 选项来忽略这个异常
external关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(location )
like允许用户复制现有的表结构,但是不复制数据
comment 可以为表与字段增加描述
[ROW FORMAT DELIMITED]关键字,是用来设置创建的表在加载数据的时候,支持的列分隔符。不同列之间用一个’\001’分割,集合(例如array,map)的元素之间以’\002’隔开,map中key和value用’\003’分割。
用户在建表的时候可以自定义 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 table pokes (foo int, bar string);
创建外部表:
create external table page_view(viewTime int, userid bigint,
page_url string, referrer_url string,
ip string comment 'IP Address of the User',
country string comment 'country of origination')
comment 'This is the staging page view table'
row format delimited fields terminated by '\054'
stored as textfile
location '';
建分区表
creat table par_table(viewTime int, userid bigint,
page_url string, referrer_url string,
ip string comment 'IP Address of the User')
comment 'This is the page view table'
partitioned by(date string, pos string)
row format delimited ‘\t’
fields terminated by '\n'
stored as sequencefile;
创建有分区的表
create table table_name (
id int,
dtDontQuery string,
name string
)
partitioned by (date string)
一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。
分区是以字段的形式在表结构中存在,通过describe table命令可以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。
在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作。有时候只需要扫描表中关心的一部分数据,因此建表时引入了partition概念。表中的一个 Partition 对应于表下的一个目录,Partition 就是辅助查询,缩小查询范围,加快数据的检索速度和对数据按照一定的规格和条件进行管理。
建Bucket表
creat table par_table(viewTime int, userid bigint,
page_url string, referrer_url string,
ip string comment 'IP Address of the User')
comment 'This is the page view table'
partitioned by(date string, pos string)
clustered by(userid) sorted by(viewTime) into 32 buckets
row format delimited ‘\t’
fields terminated by '\n'
stored as sequencefile;
创建表并创建索引字段ds
hive> creat table invites (foo int, bar string) partitioned by (ds string);
复制一个空表
creat table empty_key_value_store like key_value_store;
例子
create table user_info (user_id int, cid string, ckid string, username string)
row format delimited
fields terminated by '\t'
lines terminated by '\n';
导入数据表的数据格式是:字段之间是tab键分割,行之间是断行。
及要我们的文件内容格式:
100636 100890 c5c86f4cddc15eb7 yyyvybtvt
100612 100865 97cc70d411c18b6f gyvcycy
100078 100087 ecd6026a15ffddf5 qa000100
显示所有表:
hive> show tables;
按正条件(正则表达式)显示表,
hive> show tables '.*s';
修改表结构
1表添加一列 :
hive> alter table pokes add columns (new_col int);
2添加一列并增加列字段注释
hive> alter table invites add columns (new_col2 int comment 'a comment');
3更改表名:
hive> alter table events rename to 3koobecaf;
替换指定列
hive> alter table pokes replace columns(name string);
hive上替换列 很简单 replace 就好,但是只是在元数据中替换了而已,其实并没有改动hdfs上的数据文件
4删除列:
hive> alter table pokes drop name;
删除既存的指定列
5删除表:
hive> drop table pokes;
hive模糊搜索表
show tables like '*name*';
查看表结构信息
desc formatted table_name;
desc table_name;
增加、删除分区
1增加
alter table table_name add [if not exists] partition_spec
[ location 'location1' ] partition_spec [ location 'location2' ] ...
partition_spec:
: partition (partition_col = partition_col_value, partition_col = partiton_col_value, ...)
删除
alter table table_name drop partition_spec, partition_spec,...
查看分区信息
show partitions table_name;
根据分区查询数据
select table_coulm from table_name where partition_name = '2014-02-25';
重命名表
alter table table_name rename to new_table_name
修改列的名字、类型、位置、注释:
alter table table_name change [column] col_old_name
col_new_name column_type [comment col_comment] [first|after column_name]
ALTER TABLE table1 CHANGE col_old_name col_name String;
这个命令可以允许改变列名、数据类型、注释、列位置或者它们的任意组合
表添加一列 :
hive> alter table pokes add columns (new_col int);
添加一列并增加列字段注释
hive> alter table invites add columns (new_col2 int comment 'a comment');
增加/更新列
alter table table_name add|replace columns (col_name data_type [comment col_comment], ...)
ass是代表新增一字段,字段位置在所有列后面(partition列前)
replace则是表示替换表中所有字段。
增加表的元数据信息
alter table table_name set tblproperties table_properties table_properties:
:[property_name = property_value…..]
用户可以用这个命令向表中增加metadata
改变表文件格式与组织
alter table table_name set fileformat file_format
?alter table table_name clustered by(userid) sorted by(viewtime) into num_buckets buckets
这个命令修改了表的物理存储属性
创建/删除视图
create view [if not exists] view_name [ (column_name [comment column_comment], ...)
][comment view_comment][tblproperties (property_name = property_value, ...)] as select
增加视图
如果没有提供表名,视图列的名字将由定义的SELECT表达式自动生成
如果修改基本表的属性,视图中不会体现,无效查询将会失败
视图是只读的,不能用LOAD/INSERT/ALTER
删除视图
drop view view_name
创建数据库
create database name
显示命令
show tables;
?show databases;
?show partitions ;
?show functions
?describe extended table_name dot col_name
hive不支持用insert语句一条一条的进行插入操作,也不支持update操作。数据是以load的方式加载到建立好的表中。数据一旦导入就不可以修改。
DML包括:insert插入、update更新、delete删除
向数据表内加载文件
load data [local] inpath 'filepath' [overwrite] into table tablename
[partition (partcol1=val1, partcol2=val2 ...)]
Load 操作只是单纯的复制/移动操作,将数据文件移动到 Hive 表对应的位置。
filepath
包含模式的完整 URI,例如:hdfs://namenode:9000/user/hive/project/data1
例如:
hive> load data local inpath './examples/files/kv1.txt' overwrite into table pokes;
加载的目标可以是一个表或者分区。如果表包含分区,必须指定每一个分区的分区名
filepath 可以引用一个文件(这种情况下,Hive 会将文件移动到表所对应的目录中)或者是一个目录(在这种情况下,Hive 会将目录中的所有文件移动至表所对应的目录中)
指定了local,即本地
load 命令会去查找本地文件系统中的 filepath。如果发现是相对路径,则路径会被解释为相对于当前用户的当前路径。用户也可以为本地文件指定一个完整的 URI,比如:file:///user/hive/project/data1.
load 命令会将 filepath 中的文件复制到目标文件系统中。目标文件系统由表的位置属性决定。被复制的数据文件移动到表的数据对应的位置
数据插入
通过查询语句进行插入,这里不像是MySql可以一条一条的进行插入操作,在Hive中我试了几次都没有成功,搜了下也都是通过select语句进行插入的。这里也算是和普通的sql不同的地方吧。
3.1 基本的Select 操作
select [all | distinct] select_expr, select_expr, ...
from table_reference
[where where_condition]
[group by col_list [having condition]]
[ cluster by col_list
| [distribute by col_list] [sort by| order by col_list]
]
[limit number]
使用all和distinct选项区分对重复记录的处理。默认是all,表示查询所有记录。distinct表示去掉重复的记录
Where 条件: 类似我们传统SQL的where 条件
目前支持 and,or,0.9版本支持between
int, not in
不支持exist,not exist
order by与sort by的不同
order by全局排序,只有一个Reduce任务
sort by只在本机做排序
limit:limit 可以限制查询的记录数
select * from t1 limit 5
实现Top k 查询
下面的查询语句查询销售记录最大的 5 个销售代表。
set mapred.reduce.tasks = 1
select * from test sort by amount desc limit 5
regex column specification
select 语句可以使用正则表达式做列选择,下面的语句查询除了 ds 和 hr 之外的所有列:
select `(ds|hr)?+.+` from test
1、Hive不支持等值连接
SQL中对两表内联可以写成:
select * from dual a,dual b where a.key = b.key;
Hive中应为
select * from dual a join dual b on a.key = b.key;
而不是传统的格式:
SELECT t1.a1 as c1, t2.b1 as c2 from t1, t2 where t1.a2 = t2.b2
2、分号字符
分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:
select concat(key,concat(';',key)) from dual;
但HiveQL在解析语句时提示:
FAILED: Parse Error: line 0:-1 mismatched input '' expecting ) in function specification
解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:
select concat(key,concat('\073',key)) from dual;
3、is [not] null
SQL中null代表空值, 值得警惕的是, 在HiveQL中String类型的字段若是空(empty)字符串, 即长度为0, 那么对它进行is null的判断结果是False.
4、Hive不支持将数据插入现有的表或分区中,仅支持覆盖重写整个表,示例如下:
insert overwrite table t1
select * from t2;
hive -e "sql语句"
hive -e "show tables" #查看有哪些表
会将查询的结果打印在控制台上。
hive -e "sql语句" >> xxx
hive -e "show tables" >> wujiadong #将查看结果追加到wujiadong文件中
会将查询的结果重定向到xxx文件中,会显示OK和抓取的数据条数
hive -S -e "sql语句" >> xxx
hive -S -e "show tables" >> wujiadong #将查看结果追加到wujiadong文件中
会将查询的结果重定向到xxx文件中,不会显示OK和抓取的数据条数
hive -f sqlfile
hive -f 1.sql #直接跟一个文件,执行后退出
执行文件中的sql(用于sql比较长的时候), 执行完后就退出
hive -i sqlfile
hive -i 1.sql #执行之后还可以继续执行
执行文件中的sql(用于sql比较长的时候), 执行完后就不退出,还可继续执行其他sql。在这种模式下若还要去执行其他文件中的sql, 需要在hive模式中使用 source sqlfile 来配合。
由于hive已经是运行在hadoop上所以直接可以使用 dfs + hdfs命令;
hive> dfs -ls / ; #查看hdfs下目录
hive> dfs -mkdir /hahaha; #hdfs下创建目录hahaha
当我们进去hive模式时,执行hive脚本,可以使用“! + linux”命令
hive> !pwd; #查看路径
hive> !ls; #查看有哪些文件
本节说明如何通过把Hive中的数据备份到磁盘中,并从磁盘中恢复到Hive中。
1,把Hive中的表数据备份到磁盘中。
备份示例:
use GRC_BIGDATA;
insert overwrite local directory '/root/grc_bigdata/backup/src_companyinfo' ROW FORMAT DELIMITED FIELDS TERMINATED BY '|' STORED AS TEXTFILE select * from src_companyinfo;
以上语句说明,把src_companyinfo表中的数据以‘|’为分隔符号,并备份到“/root/grc_bigdata/backup/src_companyinfo”目录中。
备份之后的目录结构如下:
root@cdh-node3 src_companyinfo]# ll
总用量 11580
-rw-r--r-- 1 root root 8482661 11月 11 19:38 000000_0
-rw-r--r-- 1 root root 2261124 11月 11 19:38 000001_0
-rw-r--r-- 1 root root 1109324 11月 11 19:38 000002_0
2,把磁盘中的文件恢复到Hive中。
先在hive中执行建表脚本:
CREATE TABLE IF NOT EXISTS src_xtbillmx2013_st
(
twbmoneyf double,
cxbz double,
......
paixu double,
ywlxid string,
swbz double
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '|' STORED AS TEXTFILE;
然后在Hive中执行如下导入命令:
use GRC_BIGDATA;
LOAD DATA LOCAL INPATH '/root/grc_bigdata/backup/src_xtbill2013_st' OVERWRITE INTO TABLE src_xtbill2013_st;
3,在Hive中备份46个表、一共552GB的数据到Linux文件系统,一共耗时55386 秒,大概15.4个小时。
从Linux文件系统中恢复以上数据,耗时41217秒,大概11.4个小时。