优点:
1. 学习成本低,只要会sql就能用hive
2. 开发效率高,不需要编程,只需要写sql
3. 模型简单,易于理解
4. 针对海量数据的高性能查询和分析
5. HiveQL 灵活的可扩展性(Extendibility)
6. 高扩展性(Scalability)和容错性
7. 与 Hadoop 其他产品完全兼容
缺点:
1. 不支持行级别的增删改
2. 不支持完整的在线事务处理
3.本质上仍然是MR的执行,效率不算高
由于 Hive 的查询是通过 MapReduce 框架实现的,而 MapReduce 本身就是为实现针对海量数据的高性能处理而设计的。所以 Hive 天然就能高效的处理海量数据。
与此同时,Hive 针对 HiveQL 到 MapReduce的翻译进行了大量的优化,从而保证了生成的MapReduce 任务是高效的。在实际应用中,Hive 可以高效的对 TB 甚至 PB级的数据进行处理。
HiveQL 和 SQL 非常类似,所以一个熟悉SQL 的用户基本不需要培训就可以非常容易的使用 Hive 进行很复杂的查询。
除了 HiveQL 自身提供的能力,用户还可以自定义其使用的数据类型、也可以用任何语言自定义 mapper 和 reducer 脚本,还可以自定义函数(普通函数、聚集函数)等。这就赋予了 HiveQL 极大的可扩展性。用户可以利用这种可扩展性实现非常复杂的查询。
Hive本身并没有执行机制,用户查询的执行是通过 MapReduce 框架实现的。由于MapReduce 框架本身具有高度可扩展(计算能力随 Hadoop 机群中机器的数量增加而线性增加)和高容错的特点,所以 Hive也相应具有这些特点。
Hive 自身并不存储用户数据,而是通过接口访问用户数据。这就使得 Hive支持各种数据源和数据格式。例如,它支持处理 HDFS 上的多种文件格式(TextFile、SequenceFile 等),还支持处理 HBase 数据库。用户也完全可以实现自己的驱动来增加新的数据源和数据格式。一种理想的应用模型是将数据存储在 HBase 中实现实时访问,而用Hive对HBase 中的数据进行批量分析。
在Hive中建立的一张表(可以直接在表中插入数据或者读取外部文件插入数据)。
内部表删除的时候HDFS中是数据会被删除
利用Hive创建一张表来管理HDFS里某个目录下的文件数据。
外部表可以删除但是HDFS中的数据不会被删除。
可以通过添加指定的字段提高Hive的查询效率,避免了全表遍历。
实现数据的抽样方便进行数据测试
通过hash分桶算法将数据与分放在不同的桶(hdfs中的文件)中,方便后续获取
分桶表机制默认是不开启的,需要手动开启:set hive.enforce,bucketing=true
分桶表不允许导入外部文件,只能从一张表数据导入
分桶表是内部表,解决了大表之间的join
原理:分桶的原理是根据指定的列的计算hash值模余分桶数量后将数据分开存放。方便数据抽样
一、概述
1. explode 命令可以将行数据,按指定规则切分出多行
2. 用explode做行切分,注意表里只有一列,并且行数据是string类型,因为只有字符类型才能做切分。
二、示例
原始数据:
100,200,300
200,300,500
要求:
要将上面两行数据根据逗号拆分成多行(每个数字占一行)
实现步骤
1. 上传HDFS,并创建对应的外部表,执行:create external table ex1 (num string) location '/ex';
通过explode指令来做行切分,执行:select explode(split(num,’,’)) from ex1;是根据指定的列的计算hash值模余分桶数量后将数据分开存放。方便数据抽样
import org.apache.hadoop.hive.ql.exec.UDF;
public class ToUpper extends UDF{
public String evaluate(String str){
return str.toUpperCase();
}
}
编写UDF函数的时候需要注意一下几点:
a)自定义UDF需要继承org.apache.hadoop.hive.ql.UDF。
b)需要实现evaluate函数,evaluate函数支持重载。
多行进一行出,如sum()、min(),用在group by时
1.必须继承
org.apache.hadoop.hive.ql.exec.UDAF(函数类继承)
org.apache.hadoop.hive.ql.exec.UDAFEvaluator(内部类Evaluator实现UDAFEvaluator接口)
2.Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数
init():类似于构造函数,用于UDAF的初始化
iterate():接收传入的参数,并进行内部的轮转,返回boolean
terminatePartial():无参数,其为iterate函数轮转结束后,返回轮转数据,类似于hadoop的Combiner
merge():接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean
UDTF(User-Defined Table-Generating Functions) 用来解决 输入一行输出多行(On-to-many maping) 的需求。
什么是数据倾斜以及数据倾斜是怎么产生的?
简单来说数据倾斜就是数据的key的分化严重不均匀,造成一部分数据很多,一部分数据很少的局面。
业务逻辑造成的数据倾斜会多很多,日常使用过程中,容易造成数据倾斜的原因可以归纳为几点:
1)group by
2)distinct count(distinct xx)
3)join
例如:order表有1000条数据,customer表有1000条数据 mid=uid有300条,m.dt=‘20160801’有100条数据
优化前:select m.cid,u.id form order m join customer u on m.cid=u.id where m.dt=’20160801’;
解析:order表先和customer表进行全外连接查询出mid=uid的300条数据,再从三表条数据中查询出100条符合条件的数据
(10001000)+300=1000300=一百万零三百
优化后:select m.cid,u.id from (select cid from order where dt=’20160801’)m join customer u on m.cid = u.id
解析:现在order表中查询出dt=‘20160801’的数据,在进行m表和customer表的全外连接查询出m.cid=u.id的数据
1000+(1001000)=101000=十万零一千
调优参数:set hive.groupby.skewindata=true;
select count(w) from words group by w;
假设这种方式是对单词的个数进行统计
group by - 实际上对应了MapReduce中的Partition操作 - group by出来有多少个group就意 味着有多少个分区,每一个分区要对应一个ReduceTask
hello hadoop
hello hive
hello flume source
hello hadoop yarn
hello - ReduceTask
hadoop - ReduceTask
flume - ReduceTask
100G --- 60G 3G flume 5G Hadoop ...
在给定这些数据中,hello的数量偏多,flume的数据量偏少,那就意味着处理hello的ReduceTask要计算的总量要偏多 --- 数据倾斜
分而治之
数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作
由上面可以看出起到至关重要的作用的其实是第二个参数的设置,它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上,所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜
hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。
由上面可以看出起到至关重要的作用的其实是第二个参数的设置,它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上,所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜。
优化前:select count(distinct id )from tablename
去重:distinct - 无论有多少个map,在map阶段无法进行合并(combine) - 需要全部的值都发往Reduce,然后在Reduce才真正进行去重 - 如果不指定默认只有一个ReduceTask - set mapreduce.reduce.tasks = 5
聚合:因为聚合函数的参与,为了保证最后的结果会全部聚合在一块,强制只存在一个ReduceTask
优化后:select count() from (select distinct id from tablename)tmp;
虽然无法在map端去重,但是可以设置多个ReduceTask
分析:
a. 优化前
i. 由于对id=引入了distinct操作,所以在Map阶段无法利用combine对输出结果去消重,必须将id作为key输出
ii. 在reduce阶段再对来自于不同的MapTask的结果进行消重,计入最终统计值
iii. 由于ReduceTask的数量默认为1,所以导致MapTask的所有结果都只能由这一个ReduceTask处理,这就使得ReduceTask的执行效率成为整个任务的瓶颈
虽然在使用hive的时候可以通过set mapred.reduce.tasks设置ReduceTask的数量,但是Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指定的Reduce Task数,而强制使用1。
b. 优化后:
i. 利用Hive对嵌套语句的支持,将原来一个MapReduce作业转换为两个作业:在第一阶段选出全部的非重复id,在第二阶段再对这些已消重的id进行计数
ii. 在第一阶段我们可以通过增大Reduce的并发数,并发处理Map输出
iii. 在第二阶段,由于id已经消重,因此COUNT()操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。这样即使第二阶段Hive强制指定一个Reduce Task,极少量的Map输出数据也不会使单一的Reduce Task成为瓶颈
iv. 这一优化使得在同样的运行环境下,优化后的语句执行只需要原语句20%左右的时间
简单来说限制了一些字段以做到优化效果
1. 用户可以通过 set hive.mapred.mode=strict 来设置严格模式,改成unstrict则为非严格模式
2. 在严格模式下,用户在运行如下query的时候会报错:
1. 分区表的查询没有使用分区字段来限制
2. 使用了order by 但没有使用limit语句(如果不使用limit,会对查询结果进行全局排序,消耗时间长)
3. 产生了笛卡尔积
案例一
原始数据:
100,200,300
200,300,500
建表语句:
create external table ex(vals array) row format delimited fields terminated by ‘\t’ collection items terminated by ‘,’ location ‘/ex’;
查询每行数组的个数,查询语句:
select size(vals) from ex;
注:hive 内置函数不具备查询某个具体行的数组元素。需要自定义函数来实现,但这样的需求在实际开发里很少,所以不需要在意。
案例二
原始数据:
100,200,300 tom,jary
200,300,500 rose,jack
建表语句:
create external table ex1(info1 array,info2 array) row format delimited fields terminated by ‘\t’ collection items terminated by ‘,’ location ‘/ex’;
结果
原始数据:
tom,23
rose,25
jary,28
建表语句:
create external table m1 (vals map
查询语句:
select vals[‘tom’] from m1;
案列二
原始数据:
tom 192.168.234.21
rose 192.168.234.21
tom 192.168.234.22
jary 192.168.234.21
tom 192.168.234.24
tom 192.168.234.21
rose 192.168.234.21
tom 192.168.234.22
jary 192.168.234.21
tom 192.168.234.22
tom 192.168.234.23
建表语句 :
create external table ex (vals map
注意:map类型,列的分割符必须是\t
查询语句
select vals[‘tom’] from ex where vals[‘tom’] is not null;
如果想做去重工作,可以调用distinct内置函数
select distinct(ip) from (select vals[‘tom’] ip from ex where vals[‘tom’] is not null)ex1;或者select distinct(vals[‘tom’]) from m2 where vals[‘tom’] is not null;
原始数据:
tom 23
rose 22
jary 26
建表语句:
create external table ex (vals structname:string,age:int)row format delimited collection items terminated by ’ ’ location ‘/ex’;
查询语句:
select vals.age from ex where vals.name=‘tom’;
1. 用户接口主要有三个:CLI,JDBC 和 WUI
a. CLI,最常用的模式。实际上在>hive 命令行下操作时,就是利用CLI用户接口
b. JDBC,通过java代码操作,需要启动hiveserver,然后连接操作
2. Metastore
Hive将元数据存储在数据库中,如mysql、derby。Hive中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等
3. 解释器(complier)、优化器(optimizer)、执行器(executor)组件
这三个组件用于:HQL语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS中,并在随后有MapReduce调用执行
4. Hadoop
Hive的数据存储在HDFS中,大部分的查询、计算由MapReduce完成
1. 通过客户端提交一条Hql语句
2. 通过complier(编译组件)对Hql进行词法分析、语法分析。在这一步,编译器要知道此hql语句到底要操作哪张表
3. 去元数据库找表信息
4. 得到信息
5. complier编译器提交Hql语句分析方案
6. 执行流程
a. executor 执行器收到方案后,执行方案(DDL过程)。在这里注意,执行器在执行方案时,会进行判断:如果当前方案不涉及到MR组件,比如为表添加分区信息、比如字符串操作等,比如简单的查询操作等,此时就会直接和元数据库交互,然后去HDFS上去找具体数据;如果方案需要转换成MR job,则会将job 提交给Hadoop的JobTracker
b. MR job完成,并且将运行结果写入到HDFS上
c. 执行器和HDFS交互,获取结果文件信息
如果客户端提交Hql语句是带有查询结果性的,则会发生:7-8-9步,完成结果的查询。
概述
hive文件存储格式包括以下几类:
1、TEXTFILE
2、SEQUENCEFILE
3、RCFILE
4、ORCFILE
5、Parquet
其中TEXTFILE为默认格式,建表时不指定默认为这个格式,导入数据时会直接把数据文件拷贝到hdfs上不进行处理。
SEQUENCEFILE,RCFILE,ORCFILE格式的表不能直接从本地文件导入数据,数据要先导入到textfile格式的表中, 然后再从表中用insert导入SequenceFile,RCFile,ORCFile表中。
一、TEXTFILE
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。
可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
示例:
create table if not exists textfile_table(
site string,
url string,
pv bigint,
label string)
row format delimited
fields terminated by ‘\t’
stored as textfile;
插入数据操作:
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec;
insert overwrite table textfile_table select * from textfile_table;
二、SEQUENCEFILE
SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。
SequenceFile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。
示例:
create table if not exists seqfile_table(
site string,
url string,
pv bigint,
label string)
row format delimited
fields terminated by ‘\t’
stored as sequencefile;
插入数据操作:
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec;
SET mapred.output.compression.type=BLOCK;
insert overwrite table seqfile_table select * from textfile_table;
,完成结果的查询。