Hive
概述
Hive是基于Hadoop的一个数据仓库工具。可以将结构化的数据文件映射为一张表,并提供完整的sql查询功能,可以将sql语句转换为MapReduce任务运行。其优点是学习成本低,可以通过类SQL语句快速实现MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取、转化、加载(ETL Extract-Transform-Load ),也可以叫做数据清洗,这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 HiveQL,它允许熟悉 SQL 的用户查询数据。
Hive 构建在基于静态(离线)批处理的Hadoop 之上,Hadoop 通常都有较高的延迟并且在作业提交和调度的时候需要大量的开销。Hive 的最佳使用场合是大数据集的离线批处理作业,例如,网络日志分析。
HQL
HQL - Hive通过类SQL的语法,来进行分布式的计算。HQL用起来和SQL非常的类似,Hive在执行的过程中会将HQL转换为MapReduce去执行,所以Hive其实是基于Hadoop的一种分布式计算框架,底层仍然是MapReduce,所以它本质上还是一种离线大数据分析工具。
数据仓库的特征
- 数据仓库是多个异构数据源所集成的。
- 数据仓库存储的一般是历史数据。大多数的应用场景是读数据(分析数据),所以数据仓库是弱事务的。
- 数据库是为捕获数据而设计,数据仓库是为分析数据而设计。
- 数据仓库是时变的,数据存储从历史的角度提供信息。即数据仓库中的关键结构都隐式或显示地包含时间元素。
- 数据仓库是弱事务的,因为数据仓库存的是历史数据,一般都读(分析)数据场景。
数据库属于OLTP系统。(Online Transaction Processing)联机事务处理系统。涵盖了企业大部分的日常操作,如购物、库存、制造、银行、工资、注册、记账等。比如Mysql,oracle等关系型数据库。
数据仓库属于OLAP系统。(Online Analytical Processing)联机分析处理系统。Hive,Hbase等
OLTP是面向用户的、用于程序员的事务处理以及客户的查询处理。
OLAP是面向市场的,用于知识工人(经理、主管和数据分析人员)的数据分析。
OLAP通常会集成多个异构数据源的数据,数量巨大。
OLTP系统的访问由于要保证原子性,所以有事务机制和恢复机制。
OLAP系统一般存储的是历史数据,所以大部分都是只读操作,不需要事务。
Hive 基础指令
Hive内部表,外部表,分区表,分桶表
内部表
先在hive里建一张表,然后向这个表插入数据(用insert可以插入数据,也可以通过加载外部文件方式来插入数据),这样的表称之为hive的内部表。当内部表被删除时,对应的HDFS的数据也会被删除掉。
外部表
HDFS里已经有数据了,比如有一个2.txt文件,里面存储了这样的一些数据:
1 jary
2 rose
然后,通过hive创建一张表stu来管理这个文件数据。则stu这样表称之为外部表。注意,hive外部表管理的是HDFS里的某一个目录下的文件数据。删除外部表,但对应的数据依然还在。
创建外部表的命令:
create external table stu (id int,name string) row format delimited fields terminated by ’ ’ location ‘/目录路径’
分区表
分区表的作用:可以避免查询整表,在生产环境下,基本都是建立带有分区字段的表,在查询时,带上分区条件。内部表和外部表都可以是分区表。
分区表在HDFS,一个分区,就对应一个目录。
分区表的实际应用:一般是以天为单位来建立分区,这样方便管理表数据,尤其是按日期查询很方便。比如:
创建分区表语法:
create table book (id int, name string) partitioned by (category string) row format delimited fields terminated by ‘\t’;
注:在创建分区表时,partitioned字段可以不在字段列表中。生成的表中自动就会具有该字段。
加载数据:load data local inpath ‘/home/cn.txt’ overwrite into table book partition (category=‘cn’);
在hdfs中手动创建目录无法被hive使用,因为元数据库中没有记录该分区,需执行:ALTER TABLE book add PARTITION (category = ‘fr’) location ‘/文件目录’;
删除分区:alter table book drop partition(category=‘cn’);
修改分区:alter table book partition(category=‘french’) rename to partition (category=‘hh’);
分桶表
原理及作用:根据指定的列的计算hash值模余分桶数量后将数据分开存放,方便数据抽样。
1.创建带桶的表:
create table teacher(name string) clustered by (name) into 3 buckets row format delimited fields terminated by ’ ';
2.开启分桶机制:
set hive.enforce.bucketing=true;
3.插入数据(对于分桶表,不允许以外部文件方式导入数据,只能从另外一张表数据导入。分桶表只能是内部表。):
insert overwrite table teacher select * from tmp;
分桶语法-TABLESAMPLE(BUCKET x OUT OF y):
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。
例如:table总共分了3份,当y=3时,抽取(3/3=)1个bucket的数据,当y=6时,抽取(3/6=)1/2个bucket的数据。
x表示从哪个bucket开始抽取。
例如:table总bucket数为3,tablesample(bucket 3 out of 3),表示总共抽取(3/3=)1个bucket的数据,抽取第3个bucket的数据。
再例如:table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
查询第一个桶里数据(总共3桶),并返回一半的数据:
select * from bucketed_user tablesample(bucket 1 out of 6 on id);
Hive数据类型
基本数据类型
复杂数据类型
数组类型 Array
1.元数据:
100,200,300
200,300,500
2.建表语句:
create external table ex(vals array<int>) row format delimited fields terminated by '\t' collection items terminated by ',' location '/ex';
map类型
1.元数据:
tom,23
rose,25
jary,28
2.建表语句:(注意:map类型,列的分割符必须是\t)
create external table m1 (vals map<string,int>) row format delimited fields terminated by '\t' map keys terminated by ',' location '/map';
3.查询语句:select vals[‘tom’] from m1;
struct类型
1.元数据:
tom 23
rose 22
jary 26
2.建表语句:
create external table ex (vals struct<name:string,age:int>)row format delimited collection items terminated by ' ' location '/ex';
3.查询语句:
select vals.age from ex where vals.name=‘tom’;
Hive常用字符串操作函数
explode命令可以将行数据按照指定的规则切分出多行
注:用explode做行切分,注意表里只有一列,并且行数据是string类型,因为只有字符类型才能做切分。
例如表数据为:
100,200,300
200,300,500
执行:select explode(split(num,’,’)) from ex1;
Hive的UDF
如果hive的内置函数不够用,我们也可以自己定义函数来使用,这样的函数称为hive的用户自定义函数,简称UDF。
实现步骤:
- 新建java工程,导入hive相关包,导入hive相关的lib。
- 创建类继承UDF
- 自己编写一个evaluate方法,返回值和参数任意。
- 为了能让mapreduce处理,String要用Text处理。
- 将写好的类打成jar包,上传到linux中
- 在hive命令行下,向hive注册UDF:add jar /xxxx/xxxx.jar
- 在hive命令行下,为当前udf起一个名字:create temporary function fname as ‘类的全路径名’;
Hive的Join操作
元数据:order表
1 20180710 P001 20
2 20180710 P002 14
3 20180710 P001 35
4 20180710 P002 40
5 20180710 P001 10
6 20180710 P003 20
7 20180710 P004 12
product表:
P001 xiaomi 2999
P002 huawei 3999
P005 chuizi 4000
建表语句:
1.create external table order_t (id string,time string,pid string,amount int) row format delimited fields terminated by ’ ’ location ‘/order’;
2.create external table product_t (pid string,name string,price int) row format delimited fields terminated by ’ ’ location ‘/product’;
查询: select * from product_t join order_t on product_t.pid=order_t.pid;
inner join: select * from product_t inner join order_t on product_t.pid=order_t.pid;
left join: select * from product_t left join order_t on product_t.pid=order_t.pid;
right join: select * from product_t right join order_t on product_t.pid=order_t.pid;
full outer join: select * from product_t full outer join order_t on product_t.pid=order_t.pid;
left semi join: 这种join解决的是exist in(是否存在) 的问题,a表里哪些数据在b表中出现过。(select * from product_t left semi join order_t on product_t.pid=order_t.pid;)
Hive数据倾斜
简单来说数据倾斜就是数据的key 的分化严重不均,造成一部分数据很多,一部分数据很少的局面。
为什么说数据倾斜与业务逻辑和数据量有关?
从另外角度看数据倾斜,其本质还是在单台节点在执行那一部分数据reduce任务的时候,由于数据量大,跑不动,造成任务卡住。若是这台节点机器内存够大,CPU、网络等资源充足,跑 80G 左右的数据量和跑10M 数据量所耗时间不是很大差距,那么也就不存在问题,倾斜就倾斜吧,反正机器跑的动。所以机器配置和数据量存在一个合理的比例,一旦数据量远超机器的极限,那么不管每个key的数据如何分布,总会有一个key的数据量超出机器的能力,造成 reduce 缓慢甚至卡顿。
数据倾斜的原因可以归纳为以下3点:
1.group by(在map阶段用key的哈希值存储解决)
2.distinct count(distinct xx)(可以将此任务分成2个mapreduce处理解决)
3.join(map side join)
Hive 优化
1.group by 优化
hive.groupby.skewindata=true数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。
2.count distinct 优化
优化前:select count(distinct id )from tablename
优化后:select count(*) from (select distinct id from tablename)tmp;
注意:count这种全局计数的操作,Hive只会用一个Reduce来实现
3.map side join
mapJoin的主要意思就是,当链接的两个表是一个比较小的表和一个特别大的表的时候,我们把比较小的table直接放到内存中去,然后再对比较大的表格进行map操作。join就发生在map操作的时候,每当扫描一个大的table中的数据,就要去去查看小表的数据,哪条与之相符,继而进行连接。这里的join并不会涉及reduce操作。map端join的优势就是在于没有shuffle,在实际的应用中,我们这样设置:set hive.auto.convert.join=true;
此外,hive有一个参数:hive.mapjoin.smalltable.filesize,默认值是25mb(其中一个表大小小于25mb时,自动启用mapjoin)
要求:在hive做join时,要求小表在前。
4.调整切片数,即map任务数(针对小文件的优化)
Hive底层自动对小文件做了优化,用了CombineTextInputFormat,将多个小文件切片合成一个切片。合成完之后的切片大小,如果>mapred.max.split.size 的大小,就会生成一个新的切片。
mapred.max.split.size 默认是128MB
set mapred.max.split.size=134217728(128MB)
对于切片数(MapTask)数量的调整,要根据实际业务来定,比如一个100MB的文件,假设有1千万条数据,此时可以调成10个MapTask,则每个MapTask处理1百万条数据。
5.JVM重用
set mapred.job.reuse.jvm.num.tasks=20(默认是1个)
JVM重用是hadoop调优参数的内容,对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况。
JVM重用可以使得一个JVM进程在同一个JOB中重新使用N次后才会销毁。
6.启用严格模式
在hive里面可以通过严格模式防止用户执行那些可能产生意想不到的不好的效果的查询,从而保护hive的集群。
用户可以通过== set hive.mapred.mode=strict ==来设置严格模式,改成unstrict则为非严格模式。
在严格模式下,用户在运行如下query的时候会报错:
①分区表的查询没有使用分区字段来限制
②使用了order by 但没有使用limit语句。(如果不使用limit,会对查询结果进行全局排序,消耗时间长)
③产生了笛卡尔积
7.关闭推测执行机制
因为在测试环境下我们都把应用程序跑通了,如果还加上推测执行,如果有一个数据分片本来就会发生数据倾斜,执行执行时间就是比其他的时间长,那么hive就会把这个执行时间长的job当作运行失败,继而又产生一个相同的job去运行,后果可想而知。可通过如下设置关闭推测执行:
set mapreduce.map.speculative=false
set mapreduce.reduce.speculative=false
set hive.mapred.reduce.tasks.speculative.execution=false
Hive 工作流程
- 通过客户端提交一条Hql语句
- 通过complier(编译组件)对Hql进行词法分析、语法分析。在这一步,编译器要知道此hql语句到底要操作哪张表
- 去元数据库找表信息
- 得到信息
- complier编译器提交Hql语句分析方案。
- a)executor 执行器收到方案后,执行方案(DDL过程)。在这里注意,执行器在执行方案时,会判断
如果当前方案不涉及到MR组件,比如为表添加分区信息、比如字符串操作等,比如简单的查询操作等,此时就会直接和元数据库交互,然后去HDFS上去找具体数据。
如果方案需要转换成MR job,则会将job 提交给Hadoop的JobTracker。
b)MR job完成,并且将运行结果写入到HDFS上。
c)执行器和HDFS交互,获取结果文件信息。 - 如果客户端提交Hql语句是带有查询结果性的,则会发生:7-8-9步,完成结果的查询。