hive可以理解为一个将SQL转换为MapReduce的任务的工具,甚至更进一步可以说hive就是一个MapReduce的客户端
Hive利HDFS存储数据,利用MapReduce查询分析数据
这里我们选用的是:Hive2.1.1
hive2.1.1下载地址
将我们的hive的安装包上传到第三台服务器的/export/softwares路径下,然后进行解压
cd /export/softwares/
tar -zxvf apache-hive-2.1.1-bin.tar.gz -C ../servers/
Hive的元数据信息:记录表和文件之间的对应关系,和记录表字段和文件字段之间的关系,本来这些元数据信息是要存到Hive自带的derby数据库中的,但是derby是有很大的缺陷,所以我们在生产环境中放弃使用derby数据库,改为mysql数据库
mysql安装教程
这里我们使用Notepad++连接hadoop连接方式参考:
Notepad++连接hadoop
cd /export/servers/apache-hive-2.1.1-bin/conf
cp hive-env.sh.template hive-env.sh
红色框框部分内容改为此内容:
HADOOP_HOME=/export/servers/hadoop-2.7.5
export HIVE_CONF_DIR=/export/servers/apache-hive-2.1.1-bin/conf
修改hive-site.xml
创建一个hive-site.xml,把以下内容添加到文件内,通过拷贝粘贴,到conf路径下
"1.0" encoding="UTF-8" standalone="no"?>
-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--指定数据库连接的用户名称-->
javax.jdo.option.ConnectionUserName</name>
root</value>
</property>
<!--指定数据库连接的密码-->
javax.jdo.option.ConnectionPassword</name>
123456</value>
</property>
<!--指定hive库的路径,和如果hive库不存在的情况下进行创建-->
javax.jdo.option.ConnectionURL</name>
jdbc:mysql://node03:3306/hive?createDatabaseIfNotExist=true&useSSL=false</value>
</property>
<!--指定数据库连接的驱动-->
javax.jdo.option.ConnectionDriverName</name>
com.mysql.jdbc.Driver</value>
</property>
<!--指定元数据是否要进行校验-->
hive.metastore.schema.verification</name>
false</value>
</property>
<!--是否要自动创建一些核心的文件-->
datanucleus.schema.autoCreateAll</name>
true</value>
</property>
<!--hive服务器绑定主机-->
hive.server2.thrift.bind.host</name>
node03</value>
</property>
</configuration>
hive使用mysql作为元数据存储,必然需要连接mysql数据库,所以我们添加一个mysql的连接驱动包到hive的安装目录下,然后就可以准备启动hive了
将我们准备好的mysql-connector-java-5.1.38.jar 这个jar包直接上传到
/export/servers/apache-hive-2.1.1-bin/lib 这个目录下即可
至此,hive的安装部署已经完成,接下来我们来看下hive的三种交互方式
node02服务器执行以下命令配置hive的环境变量
vim /etc/profile
export HIVE_HOME=/export/servers/apache-hive-2.1.1-bin
export PATH=:$HIVE_HOME/bin:$PATH
source /etc/profile
cd /export/servers/apache-hive-2.1.1-bin/
bin/hive
创建一个数据库,创建一个表,这些hive操作就会在mysql数据库中产生一条hive的元数据信息
create database if not exists mytest
use mytest
create table t_test(id int,name string)
cd /exprot/servers
vim hive.sql
脚本内容
create database if not exists mytest;
use mytest;
create table stu(id int,name string);
通过hive -f 来执行我们的sql脚本,但是我们需要先进入我们的hive安装目录
cd /export/servers/apache-hive-2.1.1-bin/
bin/hive -f /export/servers/hive.sql
create database if not exists myhive;
use myhive;
create database myhive2 location "/myhive2";
键值对信息是帮助我们来描述此数据库的基本情况和内容,方便我们快速查找所数据库
create database my_yuge with dbproperties("owner"="itcast","data"="20190508")
查看数据库的键值对信息
describe database extend my_yuge;
alter database my_yuge set dbproperties("owner"="zhangge")
desc database extended my_yuge;
删除一个空数据库,如果数据库下面有数据表,那么就会报错
drop database my_yuge;
强制删除数据库,包含数据库下面的表一起删除
drop database my_yuge cascade;
create [external] table [if not exists] table_name (
col_name data_type [comment '字段描述信息']
col_name data_type [comment '字段描述信息'])
[comment '表的描述信息'] //表示注释.默认不能使用中文
[partitioned by (col_name data_type,...)] //将表数据分为不同的文件夹目录存储
[clustered by (col_name,col_name,...)] //分桶类似于MR的分区
[sorted by (col_name [asc|desc],...) into num_buckets buckets] //排序,还可以指定排序规则
[row format row_format] //指定文件中的字段分隔符
[storted as ....] //指定hive表的数据存储类型
[location '指定表的路径'] //指定hive表文件的存储路径
说明:
关键字+[中括号]:表示可以写也可以不写
use myhive;
create table stu(id int,name string);
insert into stu values (1,"zhangsan"); #插入数据
select * from stu;
外部表说明
外部表因为是指定其他的hdfs路径的数据加载到表当中来,所以hive表会认为自己不完全独占这份数据,所以删除hive表的时候,数据仍然存放在hdfs当中,不会删掉.
内部表和外部表的使用场景
每天将收集到的网站日志定期流入HDFS文本文件。在外部表(原始日志表)的基础上做大量的统计分析,用到的中间表、结果表使用内部表存储,数据通过SELECT+INSERT进入内部表。
分别创建老师与学生表外部表,并向表中加载数据
create external table teacher(t_id string,t_name string)row format delimited fields terminated by "\t";
create external table student(t_id string,t_name string,s_birth string,s_sex string)row format delimited fields terminated by "\t";
row format delimited fields terminated by “\t"设置表字段的分隔符号为”\t",默认是-001
vim teacher.txt
1 zhangsan
2 wangwu
3 lisi
hdfs dfs -put teacher.txt /user/hive/warehouse/myhive.db/teacher
cd /export/servers
mkdir hivedatas
cd hivedatas
通过xshell的xftp上传student.csv文件到hivedatas中
load data local inpath "/export/servers/hivedatas/student.csv" into table student;
load data local inpath "/export/servers/hivedatas/student.csv" overwrite into table student;
cd /export/servers/hivedatas
hdfs dfs -mkdir -p /hivedatas
hdfs dfs -put techer.csv /hivedatas/
load data inpath "/hivedatas/teacher.csv" into table teacher;
分区表实际上就是把一个大的hive表数据分成一些小文件,然后存储在不同文件夹中
create table score(s_id string,c_id string, s_score int) partitioned by (month string) row format delimited fields terminated by '\t';
分区的核心是关键字partitioned by 后面跟上分区字段(month string)
create table score2 (s_id string,c_id string, s_score int) partitioned by (year string,month string,day string) row format delimited fields terminated by '\t';
load data local inpath '/export/servers/hivedatas/score.csv' into table score partition (month='20180101');
load data local inpath '/export/servers/hivedatas/score.csv' into table score2 partition(year='2018',month='06',day='01');
select * from score where month="20180102";
lect * from score where month = '20180101' union all select * from score where month = '20180102';
show partitions score;
alter table score add partition(month='201805');
alter table score drop partition(month = '201806');
分桶,就是将数据按照指定的字段进行划分到多个文件当中去,分桶就是MapReduce中的分区.
开启Hive的分桶功能
set hive.enforce.bucketing=true;
设置Reduce个数
set mapreduce.job.reduces=3;
创建分桶表
create table course (c_id string,c_name string,t_id string) clustered by(c_id) into 3 buckets row format delimited fields terminated by '\t';
clustered by分桶的关键字,into 3 buckets表示将我们的数据分到三个桶里面
创建普通表,这个表类似中间表,而且他的字段要和分桶表的字段一一对应起来
create table course_common (c_id string,c_name string,t_id string) row format delimited fields terminated by '\t';
向中间表中加载数据
load data local inpath '/export/servers/hivedatas/course.csv' into table course_common;
通过insert overwrite把中间表中数据加载到桶表中
insert overwrite table course select * from course_common cluster by(c_id);
这里要注意才创建分桶的时候是clustered,而在这里是不需要加ed
alter table old_table_name rname to new_table_name;
把表score4修改成score5
alter table score4 rename to score5;
desc score5
alter table score5 add columns(mycol string,mysco int);
alter table score5 change column mysco mysconew int;
drop table score5;
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]
因此,如果distribute 和sort字段是同一个时,此时,cluster by = distribute by + sort by
select * from score
select s_id,c_id from score;
1)重命名一个列。
2)便于计算。
3)紧跟列名,也可以在列名和别名之间加入关键字‘AS’
select s_id as myid ,c_id from score;
select count(1) from score;
select max(s_score) from score;
select min(s_score) from score;
select sum(s_score) from score;
select avg(s_score) from score;
LIMIT子句用于限制返回的行数。
select * from sscore limit 3;
select * from score where s_score >60;
select * from score where s_score between 80 and 100;
select * from score where s_score is null;
select * from score where s_score in(80,90);
% 代表零个或多个字符(任意个字符)。
_ 代表一个字符。
查找以8开头的所有成绩
select * from score where s_score like '8%';
查找第二个数值为9的所有成绩数据
select * from score where s_score like '_9%';
select * from score where s_id rlike '[1]';
GROUP BY语句
select s_id,avg(s_score) from score group by s_id;
select s_id,max(s_score) from score group by s_id;
HIVING语句
having与where不同点
select s_id,avg(s_score) as avgscore from score group by s_id having avgscore>85;
Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接。
案例操作: 查询分数对应的姓名
select s.s_id,s.s_score,stu.s_name,stu.s_birth from score s join student stu on s.s_id = stu.s_id;
on s.s_id = stu.s_id叫连表条件,只有符合了这个相等的字段,我们才进行连接
内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来,也就是说求两种表的交集
select * from teacher t inner join course c on t.t_id = c.t_id
左表为主,优先输出,如果右表有匹配数据的化输出,没有匹配的化右表会补一个null
select * from teacher t left join course c on t.t_id = c.t_id;
与左外连接刚好相反
注意:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生
select * from teacher t
left join course c
on t.t_id = c.t_id
left join score s
on s.c_id = c.c_id
left join student stu
on s.s_id = stu.s_id;
Order By:全局排序,只能有一个reduce
查询学生的成绩,并按照分数降序排列
select * from student s left join score sco on s.s_id = sco.s_id order by sco.s_score desc
多个列排序
select s_id,avg(s_score) avg from score group by s_id order by s_id,avg;
Sort By局部排序:可以对每个MapReduce内部进行排序
设置reduce个数
set mapreduce.job.reduces=3
查询成绩按照成绩升序排列
select * from score sort by s_score;
将查询结果导入到文件中
insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;
Distribute By:类似MR中partition,进行分区,结合sort by使用。
注意,Hive要求distribute by语句要写在sort by语句之前。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
案例实操:先按照学生id进行分区,再按照学生成绩进行排序。
set mapreduce.job.reduces=7;
insert overwrite local directory '/export/servers/hivedatas/sort' select * from score distribute by s_id sort by s_score;
CLUSTER BY
当distribute by和sort by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是倒序排序,不能指定排序规则为ASC或者DESC。
以下两种写法等价
select * from score cluster by s_id;
select * from score distribute by s_id sort by s_id;
bin/hive [-hiveconf ] [-i ] [-f|-e] [-S]
1、 -i 从文件初始化HQL。
2、 -e从命令行执行指定的HQL
3、 -f 执行HQL脚本
4、 -v 输出执行的HQL语句到控制台
5、 -p 指定服务器端口号
6、 -hiveconf 设置hive运行时候的参数配置
开发Hive应用时,不可避免地需要设定Hive的参数。设定Hive的参数可以调优HQL代码的执行效率,或帮助定位问题。
对于一般参数,有以下三种设定方式:
另外,Hive也会读入Hadoop的配置,因为Hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置。
配置文件的设定对本机启动的所有Hive进程都有效。
bin/hive -hiveconf hive.root.logger=INFO,console
hive设置日志打印级别,我要点INFO级别的信息,同时打印到console控制台
set mapred.reduce.tasks=100;
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class Captial_Udf extends UDF {
//模拟hive的upper方法:将字符串的第一个字符转为大写,其他字符不变
public Text evaluate(final Text line){
//首先做一个条件判断,如果是null或者是空,直接返回空串
if (line.toString() != null && !line.toString().equals("")){
String substring = line.toString().substring(0, 1).toUpperCase()+line.toString().substring(1);
return new Text(substring);
}
return new Text("");
}
}
cd /export/servers/apache-hive-2.7.5-bin/lib
mv test01-1.0-SNAPSHOT.jar my_upper.jar
hive的客户端添加我们的jar包
add jar /export/servers/apache-hive-2.1.1-bin/lib/my_upper.jar;
create temporary function my_upper as "itcast.Captial_Udf";
as后面是类的全路径类名
select my_upper("hello")
cd /export/servers/hadoop-2.7.5
bin/hadoop checknative
开启map输出阶段压缩可以减少job中map和Reduce task间数据传输量。具体配置如下:
set hive.exec.compress.intermediate=true;
set mapreduce.map.output.compress=true;
set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
select count(1) from score; //统计score表中有多少行数据
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress=true;
set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
insert overwrite local directory '/export/servers/snappy' select * from score distribute by s_id sort by s_id desc;
Hive支持的存储数的格式主要有:TEXTFILE(行式存储) 、SEQUENCEFILE(行式存储)、ORC(列式存储)、PARQUET(列式存储)。
存储格式 | 优劣 |
---|---|
行式存储 | 1.行查询效率高 2.列查询效率低 3.数据压缩效率低 |
列式存储 | 1.行查询效率低 2.列查询效率高 3.数据压缩效率高 |
1.创建表,存储数据格式为TEXTFILE
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE ;
load data local inpath '/export/servers/hivedatas/log.data' into table log_text ;
dfs -du -h /user/hive/warehouse/myhive.db/log_text;
原文件数据大小与textfile格式下文件大小是一致的,是因为textfile这种格式并不会对我们的数据进行压缩
create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc ;
insert into table log_orc select * from log_text ;
dfs -du -h /user/hive/warehouse/myhive.db/log_orc;
2.8M说明ORC数据格式对我们的文件进行了压缩,而且压缩的相当厉害
create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS PARQUET ;
insert into table log_parquet select * from log_text ;
dfs -du -h /user/hive/warehouse/myhive.db/log_parquet;
存储文件的压缩比总结:
ORC > Parquet > textFile
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");
insert into table log_orc_snappy select * from log_text ;
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_snappy ;
在实际的项目开发当中,hive表的数据存储格式一般选择:orc或parquet(都是列式存储)。压缩方式一般选择snappy。
Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM score;在这种情况下,Hive可以简单地读取score对应的存储目录下的文件,然后输出查询结果到控制台。通过设置hive.fetch.task.conversion参数,可以控制查询语句是否走MapReduce.
set hive.fetch.task.conversion=none;
select * from score;
select s_score from score;
select s_score from score limit 3;
set hive.fetch.task.conversion=more;
select * from score;
select s_score from score;
select s_score from score limit 3;
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务时消耗可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候会自动开启这个优化。
开启本地模式,并执行查询语句
set hive.exec.mode.local.auto=true;
select * from score cluster by s_id;
在分布式集群环境下,因为程序Bug(包括Hadoop本身的bug),负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务(比如一个作业的某个任务进度只有50%,而其他所有任务已经运行完毕),则这些任务会拖慢作业的整体执行进度。为了避免这种情况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。
设置开启推测执行参数:
set mapred.map.tasks.speculative.execution=true
set mapred.reduce.tasks.speculative.execution=true
set hive.mapred.reduce.tasks.speculative.execution=true;
关于调优这些推测执行变量,还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者Reduce task的话,那么启动推测执行造成的浪费是非常巨大大。