HDFS来存储海量的数据、MapReduce来对海量数据进行分布式并行计算、Yarn来实现资源管理和作业调度。但是面对海量的数据和负责的业务逻辑,开发人员要编写MR对数据进行统计分析难度极大,所以就产生了Hive这个数仓工具。Hive可以帮助开发人员将SQL语句转化为MapReduce在yarn上跑。
Hive是基于hadoop的一个数据仓库工具,将结构化的数据文件映射成一张表,并提供类SQL(HQL)查询功能。
1、Hive处理的数据存储在HDFS
2、Hive分析数据底层的实现是MapReduce
3、执行程序运行在Yarn上
4、结构化文件如何映射成一张表呢?借助存储在元数据数据库中的元数据来解析结构化文件。
1)用户结构:Client | CLI(command-line interface)、JDBC/ODBC(jdbc访问hive) | |
---|---|---|
2)元数据:Metastore | 元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore | |
3) Hadoop | 使用HDFS进行存储,使用MapReduce进行计算 | |
4) 驱动器:Driver | 解析器(SQL Parser) | 将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误 |
编译器(Physical Plan) | 将AST编译生成逻辑执行计划 | |
优化器(Query Optimizer) | 对逻辑执行计划进行优化 | |
执行器(Execution) | 把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark |
hive通过给用户提供的一系列交互接口,接受到的用户指令(SQL),使用自己Driver,结合元数据(metaStore),将这些指令翻译成MapReduce,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口中。
Hive | mysql | |
---|---|---|
语言 | 类sql | sql |
语言规模 | 大数据pd及以上 | 数据量小一般在百万左右到达单表极限 |
数据插入 | 能增加insert,不能update,delete | 能insert,update,delete |
数据存储 | Hdfs | 拥有自己的存储空间 |
计算引擎 | MapReduce/Spark/tez | 自己的引擎innodb |
1)修改core-site.xml
1、配置该superUser允许通过代理访问的主机节点
2、配置该superUser允许通过代理用户所属组
3、配置该superUser允许通过代理的用户
2)配置yarn-site.xml
1、NodeManager使用内存数,默认是8G,修改成4G内存
2、容器最小内存,默认512M
3、容器最大内存,默认是8G,修改成4G
4、关闭虚拟内存检查(默认开启)
3)分发修改后的配置文件
1)上传压缩包到linux的/opt/softsware目录下
2)将/opt/softsware目录下的压缩包解压到/opt/module目录下
3)将解压后的文件修改成hive
4)修改/etc/profile.d/my_env.sh文件,将hive的/bin目录添加到环境变量
这种方式适用于轻量级或者单机模式的部署,通常用于测试或开发环境。配置相对简单,但不适合高可用性和大规模部署。
1、内嵌模式示意图:
2、Derby数据库:
Derby数据库是Java编写的内存数据库,在内嵌模式中与应用程序共享一个JVM,应用程序负责启动和停止。
3、初始化Derby数据库:
1)在hive根目录下,使用/bin目录下的schematool命令初始化hive自带的Derby元数据库
2)执行上述初始化元数据库时,会发生存在jar包冲突问题
3)解决jar包冲突问题,只需要把hive的/lib目录下的log4j~.jar重命名即可
4、启动Hive
1)执行/bin目录下的hive命令,就可以启动hive,并通过cli方式连接到hive
2)使用hive
5、内嵌模式只有一个JVM进程
在内嵌模式下,命令行执行jps -ml命令,只能看到一个CliDriver进程。
这种方式更加适合生产环境,因为它支持多用户并发访问和更好的可伸延性。需要额外的配置和管理数据库服务。
1、直连模式示意图:
2、Mysql安装部署
1)检测当前系统是否安装过Mysql,如果安装过删除掉
2)将Mysql安装包上传至/opt/software目录下
3)解压到/opt/software下新建的mysql_jars目录
4)查看mysql_jars目录下文件
5)在/opt/software/mysql_jars目录下执行rpm安装,按顺序
6)如果在mysql的数据存储路径下有文件存在,需要将其全部删除,存储路径地址在/etc/my.cnf文件下datadir参数所对应的值
7)初始化数据库,查看临时的root用户的密码
8)启动mysql服务
9)登录mysql,修改root用户的密码
10)修改mysql库下的user表中的root用户允许任意ip连接
11)刷新,使得修改生效
3、配置Hive元数据库为MySQL
1)拷贝驱动
Hive需要将元数据信息存储到元数据库mysql中,需要使用JDBC的方式连接到Mysql,所以,将Mysql的JDBC驱动拷贝到Hive的lib目录下,供hive调用。
2)配置Metastore到Mysql
在/opt/module/hive/conf目录下新建hive-site.xml文件
(1)jdbc连接的URL
(2)jdbc连接的Driver
(3)jdbc连接的username
(4)jdbc连接的password
(5)Hive默认在HDFS的工作目录
(6)Hive元数据存储的验证设置false
(7)元数据存储授权设置false
4、Hive初始化元数据库
在mysql中创建hive存储元数据的数据库metastore,再通过hive的初始化元数据库操作创建表
1)登录mysql
2)新建Hive元数据库
3)初始化Hive元数据库
5、启动Hive
1)启动Hive
2)使用hive
3)开启另一个窗口测试,是否支持客户端并发操作
6、在公司生产环境中,网络环境非常的复杂,mysql的所在环境可能存在网络隔离,无法直接访问;另外,mysql的root账户和密码在此模式下会存在泄露风险,存在数据安全隐患。
在这种模式下,Hive与Hadoop生态系统中的其他组件共享元数据,这种方式可以实现元数据的高度集成和优化。
1、元数据服务模式示意图:
2、元数据服务模式
在服务器端访问MetaStore服务,客户端利用Thrift协议通过MetaStore服务访问元数据库。相比于内嵌式,这种更适合在生产环境中部署使用。
3、将Mysql作为元数据库,配置元数据服务
1)首先,将hive的元数据库配置为Mysql,编写hive-site.xml文件。在配置完后,启动hive之前必须先启动元数据服务,否则,hive启动后无法连接到元数据服务。
2)启动元数据服务
注意:启动后窗口不能再操作,需打开一个新的shell窗口做别的操作。
(1)启动hive,查看表和表中的数据,是否是Mysql数据库中的表。
(2)再另一个窗口启动hive,测试多客户端能否同时连接操作。
1、cli太过笨重,需要hive的jar支持。
1、JDBC访问Hive示意图:
2、JDBC方式访问Hive
将hive包装为服务发布出去,开发者使用JDBC的方式连接到服务,从而操作hive,减少对hive环境的依赖。
3、开启Hiveserver2
1)在hive-site.xml文件中添加如下配置信息
(1)指定hiveserver2连接的host
(2)指定hiveserver2连接的端口号
2)重启MetaStore服务
3)启动hive服务(如果是使用元数据服务的模式,需要提前开启元数据服务)
4)启动beeline服务
使用-e参数,可以不进入hive的交互窗口执行sql语句
使用-f参数,可以不进入hive交互窗口,执行脚本中sql语句
1)在/opt/module/hive/下创建datas目录并在目录下创建hive-f.sql文件
2)文件中写入正确的sql语句
3)执行文件中的sql语句,还可以将结果写入指定文件中
Hive数据类型 | Java数据类型 | 长度 |
---|---|---|
TINYINT | byte | 1byte有符号整数 |
SWALINT | short | 2byte有符号整数 |
INT | int | 4byte有符号整数 |
BIGINT | long | 8byte有符号整数 |
BOOLEAN | boolean | 布尔类型,true或者false |
FLOAT | float | 单精度浮点数 |
DOUBLE | double | 双精度浮点数 |
STRING | string | 字符系列。可以使用单引号或者双引号 |
TIMESTAMP | 时间类型 | |
BINARY | 字节数组 |
Hive的String类型不用声明其中最多能存储多少个字符,理论上它可以存储2GB的字符数。
数据类型 | 描述 | 语法示例 |
---|---|---|
STRUCT | 和c语言中的struct类似,都可以通过“点”符号访问元素内容。例如:如果某个列的数据类型是STRUCT{first STRING, last String},那么第1个元素可以通过字段.first来引用。 | struct() 例如: struct |
MAP | MAP是一组键-值对元组集合,使用数组表示法可以访问数据。例如:如果某个列的数据类型是MAP,其中键->值对是’first’->'john’和‘last’->‘doe’,那么可以通过字段名[‘last’]获取最后一个元素 | map() 例如:map |
ARRAY | 数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如:数组值为[‘john’,‘doe’] ,那么第2个元素可以通过数组名[1]进行引用 | Array() 例如:array |
1)假设某表有如下一行,我们用JSON格式来表示其数据结构。在Hive下访问的格式为
{
"name": "songsong",
"friends": ["bingbing" , "lili"] , //列表Array,
"children": { //键值Map,
"xiao song": 19 ,
"xiaoxiao song": 18
}
"address": { //结构Struct,
"street": "hui long guan" ,
"city": "beijing"
}
}
2)基于上述数据结构,我们在Hive里创建对应的表,并导入数据。
在目录/opt/module/hive/datas下创建本地测试文件personInfo.txt
songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,hui long guan_beijing
yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,chao yang_beijing
1)Hive上创建测试表personInfo
hive(default)>create table personInfo (
name string,
friends array<string>,
children map<string, int>,
address struct<street:string, city:string>
)
row format delimited
fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';
指定数据文件中行格式的分隔符
指定字段之间用’,’进行分割
指定集合类型的元素之间用’_’进行分割
指定map类型中key和value用’:’进行分割
指定行之间的分隔符为’\n’
2)上传数据到hdfs中上述表的对应路径
hadoop fs -put /opt/module/hive/datas/personInfo.txt /user/hive/warehouse/personInfo;
3)访问三种集合列里的数据,以下分别是ARRAY,MAP,STRUCT的访问方式
select
friends[1],
children['xiao song'],
address.city
from personInfo
where name="songsong";
结果:
_c0 _c1 city
lili 18 beijing
1)Hive的基本数据类型进行隐性转换类似Java
2)隐式类型转换规则如下
(1)所有整数类型都可以隐式的转换为一个范围更广的类型,如INT可以转换成BIGINT。
(2)所有整数类型、FLOAT和STRING类型都可以隐式地转换成DOUBLE。
(3)TINYINT、SMALLINT、INT都可以转换为FLOAT。
(4)BOOLEAN类型不可以转换为任何其它的类型。
3)可以使用CAST操作显示进行数据类型转换
例如:CAST(‘1’ AS INT)将把字符串‘1’转换成整数1;
1)创建数据库,数据库在HDFS上的默认存储路径是/usr/hive/warehouse/*.db。
create database bigdata;
2)避免要创建的数据库已经存在,增加if not exists判断。
create database if not exists bigdata;
3)创建一个数据库,指定数据库在HDFS上存放的位置
create database bigdata2 location '/bigdata2.db';
1)显示数据库
show databases;
2)过滤显示查询的数据库
show databases like 'bigdata*';
1)显示数据库信息
desc database bigdata;
bigdata hdfs://hadoop102:9000/user/hive/warehouse/bigdata.db atguigu USER
2)显示数据库详细信息,extended
desc database extended bigdata;
bigdata hdfs://hadoop102:9000/user/hive/warehouse/bigdata.db atguigu USER
3)创建数据库bigdata3,并设置其createtime属性
create database bigdata3 with dbproperties('createtime'='20211022');
4)再次查询
desc database bigdata3
OK
bigdata3 hdfs://hadoop102:8020/user/hive/warehouse/bigdata3.db atguigu USER
desc database extended bigdata3
OK
bigdata3 hdfs://hadoop102:8020/user/hive/warehouse/bigdata3.db atguigu USER {createtime=20211022}
use bigdata;
用户可以使用ALTER DATABASE命令为某个数据库的DBPROPERTIES设置键-值对属性值,来描述这个数据库的属性信息。
alter database bigdata set dbproperties('createtime'='20211022');
1)删除空数据库
drop database if exists bigdata2
2)如果数据库不为空,可以采用cascade命令,强制删除
drop database bigdata cascade;
1)建表语句
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
[LIKES existing_table_or_view_name]
2)字段解释说明
CREATE TABLE | 创建一个指定名称的表。如果相同名称的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项忽略这个异常 |
---|---|
EXTERNAL | 1)关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径(LOCATION)2)在删除表的适合,内部表的元数据和数据都被一起删除,外部表只删除元数据,不删除数据。 |
COMMENT | 为表和列添加注释 |
PARTITIONED BY | 创建分区表 |
CLUSTERED BY | 创建分桶表 |
SORTED BY | 不常用,对桶中的一个或多个列另外排序 |
ROW FROMAT | Fields 指定字段之间的分隔符;Collection 用于指定集合中元素的分隔符等 |
STORE AS | 指定存储文件类型:如SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件) |
LOCATION | 指定表在HDFS上的存储位置 |
AS | 后跟查询语句,根据查询语句结果创建表 |
LIKE | 允许用户复制现有的表结构,但是不复制数据 |
1)理论
2)案例实操
创建数据文件,在/opt/module/hive/datas目录下创建文件student.txt,编辑如下内容:
vim student.txt
1001 ss1
1002 ss2
1003 ss3
1004 ss4
1005 ss5
1006 ss6
1007 ss7
1008 ss8
1009 ss9
(1)创建内部表student
create table if not exists student(
id int,
name string
)
row format delimited
fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/student';
(2)查询表的类型
desc formatted student;
Table Type: MANAGED_TABLE
(3)根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student2 as select id, name from student;
(4)根据已经存在的表结构创建表
create table if not exists student3 like student;
(5)查询表的类型
desc formatted student2;
Table Type: MANAGED_TABLE
(6)删除表student2后,观察表的元数据和数据文件是否还存在
drop table student2;
1、理论
因为表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
元数据信息:指存储在Hive元数据仓库中的关于表的信息,例如表名、表结构(列名和数据类型)、表的物理位置(文件路径)等。这些信息帮助Hive了解如何访问和解释存储在外部位置的数据。
2、管理表和外部表的使用场景
外部表多用来存储原始数据,采用外部表交易共享数据。在原始数据基础上做大量的统计分析,中间用到的中间表、结果表多存于内部表。
3、案例实操
1)创建teacher.txt
1001 teacher1
1002 teacher2
1003 teacher3
1004 teacher4
1005 teacher5
2)上传数据到HDFS
hadoop fs -mkdir -p /school/teacher
hadoop fs -put teacher.txt /school/teacher
3)在hive中创建外部表teacher
create external table if not exists teacher(
id int,
name string
)
row format delimited fields terminated by '\t'
location '/school/teacher';
4)查看创建的表
show tables;
5)查看表格式化信息
desc formatted dept;
Table Type: EXTERNAL_TABLE
6)删除外部表,观察表的元数据和相应hdfs中的数据
drop table dept;
外部表删除后,hdfs中的数据还在,但是metadata中dept的元数据已被删除
1)查询表的类型
desc formatted student2;
Table Type: MANAGED_TABLE
2)修改内部表student2为外部表
alter table student2 set tblproperties('EXTERNAL'='TRUE');
3)查询表的类型
desc formatted student2;
Table Type: EXTERNAL_TABLE
4)修改外部表student2为内部表
alter table student2 set tblproperties('EXTERNAL'='FALSE');
1、语法
ALTER TABLE table_name RENAME TO new_table_name
2、实操案例
alter table student3 rename to student4;
1、语法
1)更新列
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]
2)增加和替换列
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
2、实操案例
1)查询表结构
desc test2;
OK
col_name data_type comment
id int
2)更新列:将列名id修改为student_id,类型不变
alter table test2 change column id student_id int;
OK
Time taken: 0.083 seconds
desc test2;
OK
col_name data_type comment
student_id int
3)更新列:不修改列名,仅修改列的类型为string
alter table test2 change column student_id student_id string;
OK
Time taken: 0.083 seconds
desc test2;
OK
col_name data_type comment
student_id string
4)新增列:向test2表中新增一列,列名为name,类型为string
alter table test2 add columns(name string);
desc test2;
OK
col_name data_type comment
student_id string
name string
5)调整列的位置:现在想让name的列在最前面,做如下操作
alter table test2 change name name string first;
OK
Time taken: 0.139 seconds
desc test2;
OK
col_name data_type comment
name string
student_id string
Time taken: 0.036 seconds, Fetched: 2 row(s)
6)调整列的位置:将name更新到指定列的后面,操作如下
alter table test2 change name name string after student_id;
OK
Time taken: 0.069 seconds
desc test2;
OK
col_name data_type comment
student_id string
name string
Time taken: 0.033 seconds, Fetched: 2 row(s)
7)替换列(替换所有的列)
alter table test2 replace columns(id double);
OK
Time taken: 0.058 seconds
desc test2;
OK
col_name data_type comment
id double
Time taken: 0.032 seconds, Fetched: 1 row(s)
drop table test2;
truncate table student;
注意:truncate 只能删除管理表,不能删除外部表中数据
1、基本语法
load data [local] inpath '数据的path' [overwrite] into table table_name [partition (partcol1=val1,…)];
Load data | 加载数据 |
---|---|
Local | 表示从本地加载数据到hive表,否则是从HDFS加载数据到Hive表 |
Inpath | 表是加载数据的路径 |
Overwrite | 表示覆盖表中已有数据,否则表示追加 |
Into table | 表示加载数据到哪张表中 |
Partition | 表示加载数据到指定分区 。通过分区,可以将表中的数据分散存储在不同的部分,通常基于某些列的值。例如,可以根据日期、地区等属性来分区。 |
2、实例操作
1)创建一张表student
create table student(
id string,
name string
)
row format delimited fields terminated by '\t';
2)加载本地文件到hive
load data local inpath '/opt/module/hive/datas/student.txt' into table default.student;
3)加载HDFS文件到hive中
(1)上传文件到HDFS
dfs -put /opt/module/hive/datas/student.txt /input;
(2)加载HDFS上数据
load data inpath '/input/student.txt' into table default.student;
4)加载数据覆盖表中已有的数据
load data inpath '/input/student.txt' overwrite into table default.student;
FAILED: SemanticException Line 1:17 Invalid path ''/input/student.txt'': No files matching path hdfs://hadoop102:8020/input/student.txt
竟然报错了,信息显示文件不存在?
显然,加载HDFS上的文件到hive表中,采用的类似剪切的方式,将文件拷贝到表的映射目录下。
上传文件到HDFS
dfs -put /opt/module/hive/datas/student.txt /input;
加载HDFS上数据
load data inpath '/input/student.txt' overwrite into table default.student;
1)创建一张表
create table student2(id int, name string) row format delimited fields terminated by '\t';
2)基本插入数据
insert into table student2 values(1,'wangwu'),(2,'zhaoliu');
3)将查询结果插入表中
insert overwrite table student2 select id, name from student ;
insert into | 以追加数据的方式插入到表或分区,原有数据不会删除 |
---|---|
insert overwrite | 会覆盖表中已存在的数据 |
注意:insert不支持只插入部分数据
根据查询结果创建表
create table if not exists student4
as select id, name from student;
1、上传数据到hdfs上
dfs -mkdir /input/student;
dfs -put /opt/module/hive/datas/student.txt /input/student/student.txt;
2、创建表,并指定在hdfs上的位置
create external table if not exists student5(
id int,
name string
)
row format delimited fields terminated by '\t'
location '/input/student';
3、查询数据
select * from student5;
OK
student5.id student5.name
1001 ss1
1002 ss2
……
注意:hive创建表时,默认将表的名称作为默认HDFS上表对应的存储路径的名称,但是,如果你通过location指定存储路径,就不会修改路径名称为表名了。如上边的表名为student5和其在HDFS上的存储路径student。
1、将查询的结果导出到本地
insert overwrite local directory '/opt/module/hive/datas/export/student'
select * from student;
2、将查询的结果格式化导出到本地
insert overwrite local directory '/opt/module/hive/datas/export/student'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from bigdata1.student;
3、将查询的结果导出到HDFS上(没有local)
insert overwrite directory '/output/student'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
select * from student;
注意:insert导入时,hive会自动创建导出目录,但是由于是overwrite,所以导出路径一定要写准确,否则存在误删数据的可能。
export 和 import命令主要用于两个Hadoop平台集群之间Hive表迁移。(元数据源+真实数据)
export table default.student2 to '/地址'; 导出到哪里
import table student2 from '/地址 '; 从哪里导入
注意:先用export导出后,再将数据导入。