Hive简介

hive详解 hive入门必看


上图是OLAP引擎整体架构图,分为三个层面:数据存储层,计算资源层以及OLAP服务层。(我们从olap引入hive,如果重点关注hive,这部分作为扩展即可。)

OLAP引擎是基于Spark和Hadoop的SQL引擎,内部依赖Druid,HDFS,HIVE存储来存储相关数据。为了与离线计算集群解耦,OLAP自身内部有一套完整的HDFS存储,HIVE存储以及Yarn资源池。

OLAP引擎外部对底层HIVE访问需要通过API层进行转发,比如新增分区,修改表结构等,运行在离线计算集群上的加速等任务无法操作OLAP引擎底层Hive数据仓库。
-----数据仓库-----

Hive是数据仓库,与传统的数据库(mysql、oracle等)不同,但是hive也并不是Nosql。数据库主要处理用于事务处理,也就是对操作性数据进行增删改查;而数据仓库主要作用于分析处理、挖掘信息,可以说hive只适合于批量数据的统计分析。数据仓库就等同于一种分析型数据库。
Hive与传统数据库的比较:

HIVE RDBMS
存储位置 Hdfs LocalFS
查询语言 Hql Sql
执行 MR Executor
执行延迟 高 低
处理规模 大 小
可扩展性 高 低
加载模式 读时模式 写时模式
对关系型数据库而言,加载数据时就会检查数据是否符合表模式,不符合就会拒绝加载,叫做“写时模式”,写时模式在加载数据时会校验数据,并且会对数据建索引,压缩数据,所以加载数据会很慢,但是加载完成后查询时,速度会很快;而hive在加载数据时不会去检查数据,你可以load任何格式的数据,包括图片等都可以load进去,但是在select的时候会检查表内数据格式,叫做“读时模式”。
-----存储-----
Hive的元数据存储在关系型数据库中;表数据存储依赖于hdfs,是存储在hdfs上的,具体又分为内部表和外部表:
① 内部表数据由Hive自身管理,外部表数据由HDFS管理;
② 删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
③ 无论内部表还是外部表,导入hdfs数据是mv,导入本地数据是copy
1) 元数据(metadata)
元数据是用来存储表数据信息的,比如表名,字段名,字段类型,存储位置等等,通常存储在mysql中,mysql地址可从hive-site.xml查找。
SELECT count(*) TABLES, table_schema FROM information_schema.TABLES where
table_schema = ‘hive_bigquery_metastore’ GROUP BY table_schema;

2)内部表(managed table):
内部表数据由Hive自身管理,因为底层是hdfs,所以,所谓的hive内部是相对于外部表来说的,数据还是存储在hdfs上。
Hive默认建的是内部表:
create table test_inout(A int,name string); //建表语句,建表成功后,会在hdfs上新建存储该表数据的目录;
load data inpath ‘/user/olap/hive/4.txt’ into table test_inout;
//导入hdfs上的数据,导入之后可以在50070页面查看变化,一个是看’/user/olAp/hive/4.txt’已经被删除,转移到test_inout目录下了。

默认分隔符是^A,ASCII的码控制符\001,用ctrl+v然后再ctrl+a可以敲出来,所以一般建表时会指定分隔符
create table test_inn(id int,name string) fields terminated by ‘,’;

假如load的数据文件分隔符与表约定的分隔符不一致,仍可load成功,但是查询时会是null数据。这是hive的一个特性:load数据时不会做格式检查,只是将文件拷贝到对应的目录下,在查询时才会将文件数据与表定义的格式做比较。
当删除内部表时,底层hdfs的数据同步被删除,这是内部表与外部表的区别之一。
3)外部表(external table)
外部表建表
与内部表建表语句类似,只是多了一个external。适用场景:同样的数据需要被多人分享时。比如对于一些原始日志文件,同时被多个部门同时操作的时候就需要使用外部表,如果不小心将meta
data删除了,HDFS上 的data还在可以恢复,增加了数据的安全性。
create external table test_out (id int,name string) row format delimited
fields terminated by ‘,’;
load data local inpath “/home/bigdata/shenyuqiang/out.txt” into table
test_out;


但是外部表不能使用truncate来清数据;而使用drop时,外部表只是删除meta信息,data数据还是存储在hdfs上不会被删掉,meta信息是否被删除可以去元数据库里tbls表里验证

对于hdfs上数据是否删除,最直观的是检查50070页面,也可使用hdoop命令查看;不指定location建表,hive会在默认位置存放表数据

总的来说,导入数据时,导入到内部表,是导入到自己的内部目录下,由hive管理;而导入到外部表则不由hive管理。
删除数据时,删除内部表,是同时删除了的元数据和表数据;而删除外部表数据只是删除了 元数据。
-----存储格式 parquet-----
官方:”为Hadoop生态系统中的任何项目提供压缩,高效的列式数据”
所以要了解parquet,先了解列存。列式存储(ColumnAr or
column-bAsed)是相对于传统关系型数据库的行式存储(Row-bAsedstorAge)来说的。简单来说两者的区别就是如何组织表。
示例表,有3个字段

A(int) B(string) C(string)
1 B1 C1
2 B2 C2
3 B3 C3 行存储逻辑图
1 B1 C1 2 B2 C2 3 B3 C3 列存逻辑图
1 2 3 B1 B2 B3 C1 C2 C3
• 列存查询的时候不需要扫描全部的数据,而只需要读取每次查询涉及的列,这样可以将I/O消耗降低N倍
• 由于每一列的成员都是同质的,可以针对不同的数据类型使用更高效的数据压缩算法,进一步减小I/O。
• 由于每一列的成员的同构性,可以使用更加适合的编码方式。
存储方式主要分为行存与列存,二者互有优缺点:

行存 列存
数据写入 一次写入,数据完整性得到保证 拆分成多列写入,IO高 行存占优
数据修改 指定位置修改一次 需定位到多个列的位置写入,磁头移动高 行存占优
数据读取 整存整取,一次取出一行数据;行数据有多种类型字段,解析会消耗大量cpu 只取需要用到的列;数据同质,利于解析 列存更适于大数据分析
针对以上的优缺点,可以设想下如何优化: 行存缺点就是会产生冗余数据,第一,在设计表的时候就注意避免冗余列的产生;
第二是优化数据存储记录结构,保证从磁盘读取的数据进入内存后,能快速分解消除冗余列。
列存缺点是数据写入完整性不缺定、写入效率低,可以考虑在写入过程中加入类似关系型数据库中的“回滚”机制,一旦某列写失败,此前写入的数据全部失效;写入效率低的应对方案,可以增加硬盘的方式多线程并行写入,但是要考虑成本。
大多数公司的列存采用的是parquet存储格式,比如新建数据集等,面向分析的列存储文件格式;


-----分区分桶-----
在hive
select查询时,会扫描全表,对大数据来说,全表扫描消耗的时间是巨大的,甚至会卡死。所以引入分区的概念,只查询我们所关心的部分数据,简单来说分区就是集合,就是把一个或几个字段作为分区字段,符合分区条件的数据就会落到对应的分区集合中。企业中最常见的就是以时间作为分区,每天的数据入到当天的分区里,表下存在对应的分区目录,
hdfs上可以明显的看到表与分区的层级关系。这样就大大提高了查询效率。但是在实际生产中,分桶策略使用频率较低,更常见的还是使用分区。
Create table test_partition (A int,name string) partitioned by (dates string);

在表或分区之上,hive可以继续对数据进行更细粒度的划分,也就是分桶。

* 为什么分桶
主要是为了获取更高的查询处理效率。桶为表加上了额外的结构,Hive
在处理有些查询时能利用这个结构。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大减少JOIN的数据量。
以下面为例:select A.a,A.name <http://A.name>,b.addr from A join b on A.a = b.a;
如果A表和b表已经是分桶表,而且分桶的字段是a字段,那么做这个操作的时候就不需要再进行全表笛卡尔积了,用8条数据测试二者相差2秒。
create table t_buck(A int,name string) clustered by (A) into 4 buckets;
【create table t_buck_copy(A int,name string);
load data local inpath ‘/home/bigdata/shenyuqiang/hash.txt’ into table
t_buck_copy;】
set hive.enforce.bucketing= true; //强制分桶
set mapreduce.job.reduces=4;
insert into t_buck select * from t_buck_copy cluster by (A);
//桶表不能通过load的方式直接加载数据,只能从另一张表中插入数据,且执行时,reduce个数与桶个数相同

select * from t_buck tablesample(bucket 1 out of 4 on A);
select test_inout.name,test_inn.name from test_inout,test_inn where
test_inout.A = test_inn.A; 普通表
select test_buck1.name,test_buck2.name from test_buck1,test_buck2 where
test_buck1.A=test_buck2.A; 桶表


2.怎么分桶–数据分桶的原理:
跟MR中的HashPartitioner的原理一模一样
MR中:按照key的hash值对reduceTask的个数取模。
Hive中:按照分桶字段的hash值对分桶的个数做取模运算,以此决定该条记录存放在哪个桶当中,最大化程度上保证数据的平均分配。
做hash运算时,hash函数的选择取决于分桶字段的数据类型
抽样语句:select * from test_buck tablesample(bucket x out of y on A);
x表示从哪个bucket开始抽取,y表示相隔多少个桶再抽取。y必须是table总bucket数的倍数或者因子
例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,y=4时,抽取(4/4=)1个bucket; select * from
test_buck tAblesAmple(bucket 1 out of 2 on A);
例如,table总bucket数为4,tablesample(bucket 1 out of
2),表示总共抽取(4/2=)2个bucket的数据,分别为第1个bucket和第(1+2=3)个bucket的数据。select * from
test_buck tAblesAmple(bucket 1 out of 2 on A);
所以如果想看每个bucket里存储的数据,y取bucket个数的数值,x从1取到y
3.基于分区的基础上分桶
create table test_buck4(A int,name string) partitioned by (dates string)
clustered by(A) sorted by (A asc) into 4 buckets row format delimited fields
terminated by ‘,’;

insert into table test_buck4 partition(dates=‘20180909000000’) select A,name
from test_buck4_copy where dates=’ 20180909000000’ cluster by (A);


-----Hql-----
Hive的出现目的是为了简化MapReduce编程,本着会sql的总比会Java的多的现象特点,但是hive分析数据底层的实现是转换成MR。成本低
CREATE TABLE test_0807_01(
A int,
name string)
PARTITIONED BY (
dates string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ‘|’
COLLECTION ITEMS TERMINATED BY ‘_’;
1)UDF用户自定义函数
编程步骤:

* 继承org.apache.hadoop.hive.ql.UDF
* 实现evaluate函数,该函数支持重载
First, you need to create A new class that extends UDF, with one or more
methods named evaluate.
第二步,向hive环境中添加jar:add jar /home/bigdata/shenyuqiang/HiveUDF.jar;
注册临时函数,create temporary function myudf as “hiveCon.MyUdf”;
之后就可以使用了
销毁临时函数的命令:drop temporary function xx
CREATE FUNCTION myfunc AS ‘hiveCon.MyUdf’ USING JAR
‘hdfs:///user/olap/hive/warehouse/olap.db/test_0927/HiveUDF.jar’;
2)核心:hql怎么转换成mapreduce

驱动器:driver
包含:解析器、编译器、优化器、执行器

解析器:将sql字符串转换成抽象语法树AST,这一步一般都通过第三方工具库完成,比如Antlr;将AST进行语法分析,比如表是否存在、字段是否存在、sql语义是否有误.
编译器:将AST编译生成逻辑执行计划
优化器:对逻辑执行计划进行优化
执行器:把逻辑执行计划转换成可以运行的物理计划。对hive来说,就是翻译成mapreduce.
-----运维-----
日志定位
在启动hive的时候,可以看到日志初始化的信息,日志相关信息就配置在hive-log4j.properties文件中的hive.log.dir

通过修改以下配置,使打印出来的信息带db.tableName


几种临时参数的设置,只在当前有效,退出后失效。
hive> set mapred.reduce.tasks = 6; //hiveShell设置启动6个任务
hive --hiveconf hive.root.logger=INFO,console; //启动hive时设置将日志打印在控制台

在hive中也可操作dfs命令,查看hdfs文件系统
dfs -lsr /user/olap/hive/warehouse/olap.db;

同样,也支持部分操作本地文件系统的命令,需要在命令前加!

Hive的几种交互方式
hive –help
-d,–define <key=value> VAriAble subsitution to Apply to hive
commAnds. e.g. -d A=B or --define A=B
–database Specify the database to use
-e SQL from command line
-f SQL from files
-H,–help Print help informAtion
–hiveconf <property=value> Use value for given property
–hivevar <key=value> VariAble subsitution to Apply to hive commands. e.g.
--hivevar A=B

===============================
-i InitiAlizAtion SQL file
-S,–silent Silent mode in interActive shell
-v,–verbose Verbose mode (echo executed SQL to the
console)
修复分区的两种方式
msck repair table tablename;
alter table teblename add partition();
-----总结-----
HIVE:
*处理的数据存储在hdfs
*分析数据底层实现是mapreduce
*程序运行在yarn
Sql on hadoop
Hive的强大之处在于对数据的ETL处理
抽取(extract)、交互转换(transform)、加载(load)