什么是 Hive
Hive:由 Facebook 开源用于解决海量结构化日志的数据统计。
Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类 SQL 查询功能。基于一个统一的查询分析层,通过SQL语句的方式对HDFS上的数据进行查询、统计和分析。
Hive本质是将 HQL 转化成 MapReduce 程序
Hive的表本质就是Hadoop的目录/文件
Hive默认表存放路径一般都是在你工作目录的hive目录里面,按表名做文件夹分开,如果你有分区表的话,分区值是子文件夹,可以直接在其它的M/R job里直接应用这部分数据
引入原因:
– 对存在HDFS上的文件或HBase中的表进行查询时,是要手工写一堆MapReduce代码
– 对于统计任务,只能由懂MapReduce的程序员才能搞定
– 耗时耗力,更多精力没有有效的释放出来
Hive是一个SQL解析引擎,将SQL语句转译成MR Job,然后再Hadoop平台上运行,达到快速开发的目的。
Hive中的表是纯逻辑表,就只是表的定义等,即表的元数据。本质就是Hadoop的目录/文件,达到了元数据与数据存储分离的目的
Hive本身不存储数据,它完全依赖HDFS和MapReduce。
Hive的内容是读多写少,不支持对数据的改写和删除
Hive中没有定义专门的数据格式,由用户指定,需要指定三个属性:
– 列分隔符
– 行分隔符
– 读取文件数据的方法
与传统关系数据特点比较
hive和关系数据库存储文件的系统不同,hive使用的是hadoop的HDFS(hadoop的分布式文件系统),关系数据库则是服务器本地的文件系统;
• hive使用的计算模型是mapreduce,而关系数据库则是自己设计的计算模型;
• 关系数据库都是为实时查询的业务进行设计的,而hive则是为海量数据做数据挖掘设计的,实时性很差
• Hive很容易扩展自己的存储能力和计算能力,这个是继承hadoop的,而关系数据库在这个方面要比数据库差很多。
Hive 通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的 Driver,结合元数据(MetaStore),将这些指令翻译成 MapReduce,提交到 Hadoop 中执行,最后,将执行返回的结果输出到用户交互接口。
(1)配置文件方式
默认配置文件:hive-default.xml
用户自定义配置文件:hive-site.xml
注意:用户自定义配置会覆盖默认配置。另外,Hive 也会读入 Hadoop 的配置,因为 Hive 是作为 Hadoop 的客户端启动的,Hive 的配置会覆盖 Hadoop 的配置。配置文件的设定对本机启动的所有 Hive 进程都有效。
(2)命令行参数方式
启动 Hive 时,可以在命令行添加-hiveconf param=value 来设定参数。
例如:
[atguigu@hadoop103 hive]$ bin/hive -hiveconf mapred.reduce.tasks=10;
注意:仅对本次 hive 启动有效
查看参数设置:
hive (default)> set mapred.reduce.tasks;
(3)参数声明方式
可以在 HQL 中使用 SET 关键字设定参数
例如:
hive (default)> set mapred.reduce.tasks=100;
注意:仅对本次 hive 启动有效。
查看参数设置
hive (default)> set mapred.reduce.tasks;
管理表
默认创建的表都是所谓的管理表,有时也被称为内部表。因为这种表,Hive 会(或多或少地)控制着数据的生命周期。Hive 默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。当我们删除一个管理表时,Hive 也会删除这个表中数据。管理表不适合和其他工具共享数据。
外部表
因为表是外部表,所以 Hive 并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
Hive的create创建表的时候,选择的创建方式:
– create table
– create external table
特点:
– 在导入数据到外部表,数据并没有移动到自己的数据仓库目录下,也就是说外部表中的数据并不是由它自己来管理的而内部表则不一样;
– 在删除表的时候,Hive将会把属于表的元数据和数据全部删掉;而删除外部表的时候,Hive仅仅删除外部表的元数据,数据是不会删除的!
分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
• 在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中
– 例如:pvs 表中包含 ds 和 city 两个 Partition,则
– 对应于 ds = 20090801, ctry = US 的 HDFS 子目录为:/wh/pvs/ds=20090801/ctry=US;
– 对应于 ds = 20090801, ctry = CA 的 HDFS 子目录为;/wh/pvs/ds=20090801/ctry=CA
• partition是辅助查询,缩小查询范围,加快数据的检索速度和对数据按照一定的规格和条件进行管理。
创建分区表语法
hive (default)> create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (month string)
row format delimited fields terminated by ‘\t’;
加载数据到分区表中
hive (default)> load data local inpath
‘/opt/module/datas/dept.txt’ into table default.dept_partition
partition(month=‘201709’);
hive (default)> load data
local inpath
‘/opt/module/datas/dept.txt’ into table default.dept_partition
partition(month=‘201708’);
hive (default)> load data local inpath
‘/opt/module/datas/dept.txt’ into table default.dept_partition
partition(month='201707’);
查询分区表中数据
单分区查询
hive (default)> select * from dept_partition where month=‘201709’;
多分区联合查询
hive (default)> select * from dept_partition where month=‘201709’
union
select * from dept_partition where month=‘201708’
union
select * from dept_partition where month=‘201707’;
增加分区
创建单个分区
hive (default)> alter table dept_partition add partition(month=‘201706’) ;
同时创建多个分区
hive (default)> alter table dept_partition add partition(month=‘201705’) partition(month=‘201704’);
删除分区
删除单个分区
hive (default)> alter table dept_partition drop partition (month=‘201704’);
同时删除多个分区
hive (default)> alter table dept_partition drop partition (month=‘201705’), partition (month=‘201706’);
查看分区表有多少分区
hive> show partitions dept_partition;
查看分区表结构
hive> desc formatted dept_partition;
# Partition Information
# col_name data_type comment
创建二级分区表
hive (default)> create table dept_partition2(
deptno int, dname string, loc string
)partitioned by (month string, day string)
row format delimited fields terminated by ‘\t’;
正常加载数据
(1)加载数据到二级分区表中
hive (default)>
load data local inpath ‘/opt/module/datas/dept.txt’ into table default.dept_partition2 partition(month=‘201709’, day=‘13’);
(2)查询分区数据
hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘13’;
把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式
(1)方式一:上传数据后修复
上传数据
hive (default)> dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=201709/day=12;
hive (default)> dfs -put /opt/module/datas/dept.txt /user/hive/warehouse/dept_partition2/month=201709/day=12;
查询数据(查询不到刚上传的数据)
hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘12’;
执行修复命令
hive> msck repair table dept_partition2;
再次查询数据
hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘12’;
(2)方式二:上传数据后添加分区
上传数据
hive (default)> dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=201709/day=11;
hive (default)> dfs -put /opt/module/datas/dept.txt /user/hive/warehouse/dept_partition2/month=201709/day=11;
执行添加分区
hive (default)> alter table dept_partition2 add partition(month=‘201709’, day=‘11’);
查询数据
hive (default)> select * from dept_partition2 where
month=‘201709’ and day=‘11’;
(3)方式三:创建文件夹后 load 数据到分区
创建目录
hive (default)> dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=201709/day=10;
上传数据
hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table dept_partition2 partition(month=‘201709’,day=‘10’);
查询数据
hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘10’;
创建一张表
hive (default)> create table student(id string, name string) row format delimited fields terminated by ‘\t’;
加载本地文件到 hive
hive (default)> load data local inpath ‘/opt/module/datas/student.txt’ into table default.student;
加载 HDFS 文件到 hive 中
上传文件到 HDFS
hive (default)> dfs -put /opt/module/datas/student.txt /user/atguigu/hive;
加载 HDFS 上数据
hive (default)> load data inpath ‘/user/atguigu/hive/student.txt’ into table default.student;
加载数据覆盖表中已有的数据
上传文件到 HDFS
hive (default)> dfs -put /opt/module/datas/student.txt /user/atguigu/hive;
加载数据覆盖表中已有的数据
hive (default)> load data inpath ‘/user/atguigu/hive/student.txt’ overwrite into table
default.student;
通过查询语句向表中插入数据(Insert)
1.创建一张分区表
hive (default)> create table student(id int, name string) partitioned by (month string) row format delimited fields terminated by ‘\t’;
2.基本插入数据
hive (default)> insert into table student partition(month=‘201709’) values(1,‘wangwu’);
3.基本模式插入(根据单张表查询结果)
hive (default)> insert overwrite table student partition(month=‘201708’) select id, name from student where month=‘201709’;
4.多插入模式(根据多张表查询结果)
hive (default)> from student
insert overwrite table student partition(month=‘201707’) select id, name where month=‘201709’ insert overwrite table student partition(month=‘201706’) select id, name where month=‘201709’;
查询语句中创建表并加载数据(As Select)
create table if not exists student3 as select id, name from student;
创建表时通过 Location 指定加载数据路径
1.创建表,并指定在 hdfs 上的位置
hive (default)> create table if not exists student5(
id int, name string
)
row format delimited fields terminated by ‘\t’
location ‘/user/hive/warehouse/student5’;
2.上传数据到 hdfs 上
hive (default)> dfs -put /opt/module/datas/student.txt /user/hive/warehouse/student5;
3.查询数据
hive (default)> select * from student5;
Import 数据到指定 Hive 表中
注意:先用 export 导出后,再将数据导入。
hive (default)> import table student2 partition(month=‘201709’) from ‘/user/hive/warehouse/export/student’;
Insert 导出
1.将查询的结果导出到本地
hive (default)> insert overwrite local directory ‘/opt/module/datas/export/student’
select * from student;
2.将查询的结果格式化导出到本地
hive(default)>insert overwrite local directory ‘/opt/module/datas/export/student1’
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’ select * from student;
3.将查询的结果导出到 HDFS 上(没有 local)
hive (default)> insert overwrite directory ‘/user/atguigu/student2’ ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’ select * from student;
Hadoop 命令导出到本地
hive (default)> dfs -get /user/hive/warehouse/student/month=201709/000000_0 /opt/module/datas/export/student3.txt;
Hive Shell 命令导出
基本语法:(hive -f/-e 执行语句或者脚本 > file)
[atguigu@hadoop102 hive]$ bin/hive -e ‘select * from default.student;’ >
/opt/module/datas/export/student4.txt;
Export 导出到 HDFS 上
hive (default)> export table default.student to ‘/user/hive/warehouse/export/student’;
Sqoop 导出
分区针对的是数据的存储路径;分桶针对的是数据文件。
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区,特别是之前所提到过的要确定合适的划分大小这个疑虑。
分桶是将数据集分解成更容易管理的若干部分的另一个技术。
• hive中table可以拆分成partition,table和partition可以通过‘CLUSTERED BY’进一步分bucket,bucket中的数据可以通过‘SORT BY’排序。
• ‘set hive.enforce.bucketing = true’ 可以自动控制上一轮reduce的数量从而适配bucket的个数,当然,用户也可以自主设置mapred.reduce.tasks去适配bucket个数
• Bucket主要作用:
– 数据sampling
– 提升某些查询操作效率,例如mapside join
查看sampling数据:
– hive> select * from student tablesample(bucket 1 out of 2 on id);
– tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y)
– y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了64份,当y=32
时,抽取(64/32=)2个bucket的数据,当y=128时,抽取(64/128=)1/2个bucket的数据。
–x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
注意:x 的值必须小于等于 y 的值,否则
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck
创建分桶表
create table stu_buck(id int, name string) clustered by(id) into 4 buckets
row format delimited fields terminated by ‘\t’;
查看表结构
hive (default)> desc formatted stu_buck;
Num Buckets: 4
导入数据到分桶表中
hive (default)> load data local inpath ‘/opt/module/datas/student.txt’ into table stu_buck;
空字段赋值
NVL:给值为 NULL 的数据赋值,它的格式是 NVL( string1, replace_with)。它的功能是如果string1 为 NULL,则 NVL 函数返回 replace_with 的值,否则返回 string1 的值,如果两个参数都为 NULL ,则返回 NULL。
时间类
date_format:格式化时间
select date_format(‘2019-06-29’,‘yyyy-MM-dd’);
date_add:时间跟天数相加
select date_add(‘2019-06-29’,5);
date_sub:时间跟天数相减
select date_sub(‘2019-06-29’,5);
datediff:两个时间相减
select datediff(‘2019-06-29’,‘2019-06-24’);
CASE WHEN
select
dept_id,
sum(case sex when ‘男’ then 1 else 0 end) male_count,
sum(case sex when ‘女’ then 1 else 0 end) female_count
from emp_sex group by dept_id;
行转列
CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串;
CONCAT_WS(separator, str1, str2,…):它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间;
COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生 array 类型字段。
select
t1.base,
concat_ws(’|’, collect_set(t1.name)) name
from
(select
name,
concat(constellation, “,”, blood_type) base
from
person_info) t1
group by
t1.base;
列转行
EXPLODE(col):将 hive 一列中复杂的 array 或者 map 结构拆分成多行。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和 split, explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
select
movie,
category_name
from
movie_info lateral view explode(category) table_tmp as category_name;
窗口函数
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化;
CURRENT ROW:当前行;
n PRECEDING:往前 n 行数据;
n FOLLOWING:往后 n 行数据;
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点,UNBOUNDED FOLLOWING 表示到后面的终点;
LAG(col,n):往前第 n 行数据;
LEAD(col,n):往后第 n 行数据;
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从 1 开始,对于每一行,NTILE 返回此行所属的组的编号。注意:n 必须为 int 类型。
Rank
RANK() 排序相同时会重复,总数不会变;
DENSE_RANK() 排序相同时会重复,总数会减少;
ROW_NUMBER() 会根据顺序计算。
系统内置函数
1)查看系统自带的函数
hive> show functions;
2)显示自带的函数的用法
hive> desc function upper;
3)详细显示自带的函数的用法
hive> desc function extended upper;
自定义函数
1)Hive 自带了一些函数,比如:max/min 等,但是数量有限,自己可以通过自定义 UDF来方便的扩展。
2)当 Hive 提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
3)根据用户自定义函数类别分为以下三种:
(1)UDF(User-Defined-Function)一进一出
(2)UDAF(User-Defined Aggregation Function)聚集函数,多进一出,类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions)一进多出,如 lateral view explore()
自定义函数步骤
(1)类继承
UDF继承 org.apache.hadoop.hive.ql.UDF,
UDTF继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
(2)重写方法
UDF需要实现 evaluate 函数;evaluate 函数支持重载;
(3)在 hive 的命令行窗口创建函数
a)打成jar上传至服务器,并添加 jar
add jar linux_jar_path
b)创建 function与class关联
create [temporary] function [dbname.]function_name AS class_name;
(4)在 hive 的命令行窗口删除函数
drop [temporary] function [if exists] [dbname.]function_name;
要在 Hadoop 中启用压缩,可以配置如下参数(mapred-site.xml 文件中):
Hadoop的压缩可以发生在以下3个地方
文件输入压缩
mapper输出压缩
reducer输出压缩
开启 Map 输出阶段压缩
开启 map 输出阶段压缩可以减少 job 中 map 和 Reduce task 间数据传输量。具体配置如下:
1.开启 hive 中间传输数据压缩功能
hive (default)>set hive.exec.compress.intermediate=true;
2.开启 mapreduce 中 map 输出压缩功能
hive (default)>set mapreduce.map.output.compress=true;
3.设置 mapreduce 中 map 输出数据的压缩方式
hive (default)>set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
4.执行查询语句
hive (default)> select count(ename) name from emp;
开启 Reduce 输出阶段压缩
当 Hive 将输出写入到表中时,输出内容同样可以进行压缩。属性hive.exec.compress.output 控制着这个功能。用户可能需要保持默认设置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为 true,来开启输出结果压缩功能。
1.开启 hive 最终输出数据压缩功能
hive (default)>set hive.exec.compress.output=true;
2.开启 mapreduce 最终输出数据压缩
hive (default)>set mapreduce.output.fileoutputformat.compress=true;
3.设置 mapreduce 最终数据输出压缩方式
hive (default)> set mapreduce.output.fileoutputformat.compress.codec =
org.apache.hadoop.io.compress.SnappyCodec;
4.设置 mapreduce 最终数据输出压缩为块压缩
hive (default)> set mapreduce.output.fileoutputformat.compress.type=BLOCK;
5.测试一下输出结果是否是压缩文件
hive (default)> insert overwrite local directory
‘/opt/module/datas/distribute-result’ select * from emp
distribute by deptno sort by empno desc;
文件存储格式
Hive 支持的存储数的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。
1.行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
2.列存储的特点
因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。
TEXTFILE 和 SEQUENCEFILE 的存储格式都是基于行存储的;
ORC 和 PARQUET 是基于列式存储的。
在实际的项目开发当中,hive 表的数据存储格式一般选择:orc 或 parquet。压缩方式一般选择 snappy,lzo。
<property>
<name>mapreduce.job.jvm.numtasksname>
<value>10value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
description>
property>
<property>
<name>mapreduce.map.speculativename>
<value>truevalue>
<description>If true, then multiple instances of some map tasks
may be executed in parallel.description>
property>
<property>
<name>mapreduce.reduce.speculativename>
<value>truevalue>
<description>If true, then multiple instances of some reduce tasks
may be executed in parallel.description>
property>
不过 hive 本身也提供了配置项来控制 reduce-side 的推测执行:
<property>
<name>hive.mapred.reduce.tasks.speculative.executionname>
<value>truevalue>
<description>Whether speculative execution for reducers should
be turned on.
description>
property>