我们知道大数据主要解决海量数据的三大问题:「传输问题、存储问题、计算问题」。
而 Hive 主要解决「存储和计算问题」。
Hive 是由 Facebook 开源的基于 Hadoop 的数据仓库工具,用于解决海量「结构化日志」的数据统计。
Hive 存储的数据是在 hdfs 上的,但它可以将结构化的数据文件映射为一张表,并提供类 SQL 的查询功能。(我们称之为 Hive-SQL,简称 HQL)
简单来说,Hive 是在 Hadoop 上「封装了一层 HQL 的接口」,这样开发人员和数据分析人员就可以使用 HQL 来进行数据的分析,而无需关注底层的 MapReduce 的编程开发。
所以 Hive 的本质是「将 HQL 转换成 MapReduce 程序」。
放上一张很经典的 Hive 架构图:
如上图所示:
所以 Hive 查询的大致流程为:通过用户交互接口接收到 HQL 的指令后,经过 Driver 结合元数据进行类型检测和语法分析,并生成一个逻辑方法,通过进行优化后生成 MapReduce,并提交到 Hadoop 中执行,并把执行的结果返回给用户交互接口。
Hive 采用类 SQL 的查询语句,所以很容易将 Hive 与关系型数据库(RDBMS)进行对比。但其实 Hive 除了拥有类似 SQL 的查询语句外,再无类似之处。我们需要明白的是:数据库可以用做 online 应用;而 Hive 是为数据仓库设计的。
Hive | RDBMS | |
---|---|---|
查询语言 | HQL | SQL |
数据存储 | HDFS | 本地文件系统中 |
数据更新 | 读多写少(不建议改写) | 增删改查 |
数据操作 | 覆盖追加 | 行级别更新删除 |
索引 | 0.8 版本后引入 bitmap 索引 | 建立索引 |
执行 | MapReduce | Executor |
执行延迟 | 延迟较高 | 延迟较低 |
可扩展性 | 可扩展性高 | 可扩展性低 |
数据规模 | 很大 | 较小 |
分区 | 支持 | 支持 |
总的来说,Hive 只具备 SQL 的外表,但应用场景完全不同。Hive 只适合用来做海量离线数据统计分析,也就是数据仓库。清楚这一点,有助于从应用角度理解 Hive 的特性。
在终端输入 hive -help 会出现:
usage: hive
-d,--define <key=value> Variable substitution to apply to Hive
commands. e.g. -d A=B or --define A=B
--database <databasename> Specify the database to use
-e <quoted-query-string> SQL from command line
-f <filename> SQL from files
-H,--help Print help information
--hiveconf <property=value> Use value for given property
--hivevar <key=value> Variable substitution to apply to Hive
commands. e.g. --hivevar A=B
-i <filename> Initialization SQL file
-S,--silent Silent mode in interactive shell
-v,--verbose Verbose mode (echo executed SQL to the
console)
常用的两个命令是 "-e" 和 "-f":
hive -e "select * from teacher;"
hive -f /opt/module/datas/hivef.sql
首先需要创建一张表:
create table student(
id int,
name string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
简单介绍下字段:
除此之外,还有其他的分割符设定:
这里需要注意的是 ROW FORMAT DELIMITED 必须在其它分隔设置之前;LINES TERMINATED BY 必须在其它分隔设置之后,否则会报错。
然后,我们需要准备一个文件:
# stu.txt
1 Xiao_ming
2 xiao_hong
3 xiao_hao
需要注意,每行内的字段需要用 '\t' 进行分割。
接着需要使用 load 语法加载本地文件,load 语法为:
load data [local] inpath 'filepath' [overwrite] into table tablename [partition (partcol1=val1,partcol2=val2...)]
hive> load data local inpath '/Users/***/Desktop/stu1.txt' into table student;
最后查看下数据:
hive> select * from student;
OK
1 Xiao_ming
2 xiao_hong
3 xiao_hao
Time taken: 1.373 seconds, Fetched: 3 row(s)
不过这种区别只是在旧版本中有,两者在新版本已经没有区别了。
在 hive cli 中可以用以下命令查看 hdfs 文件系统和本地文件系统:
dfs -ls /; # 查看 hdfs 文件系统
! ls ./; # 查看本地文件系统
用户根目录下有一个隐藏文件记录着 hive 输入的所有历史命令:
cat ./hivehistory
注意:hive 语句不区分大小写。
Default 的数据仓库原始位置是在 hdfs 上的:/user/hive/warehoues 路径下。如果某张表属于 Default 数据库,那么会直接在数据仓库目录创建一个文件夹。
我们以刚刚创建的表为例,来查询其所在集群位置:
hive> desc formatted student;
OK
# col_name data_type comment
id int
name string
# Detailed Table Information
Database: default
OwnerType: USER
Owner: **
CreateTime: Fri Jul 17 08:59:14 CST 2020
LastAccessTime: UNKNOWN
Retention: 0
Location: hdfs://localhost:9000/user/hive/warehouse/student
Table Type: MANAGED_TABLE
Table Parameters:
bucketing_version 2
numFiles 1
numRows 0
rawDataSize 0
totalSize 34
transient_lastDdlTime 1594948899
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params:
field.delim \t
serialization.format \t
Time taken: 0.099 seconds, Fetched: 32 row(s)
可以看到,Table Information 里面有一个 Location,表示当前表所在的位置,因为 student 是 Default 数据仓库的,所以会在 '/user/hive/warehouse/' 路径下。
如果我们想要修改 Default 数据仓库的原始位置,需要在 hive-site.xml(可以来自 hive-default.xml.template)文件下加入如下配置信息,并修改其 value:
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
<description>location of default database for the warehouse</description>
</property>
同时也需要给修改的路径配置相应的权限:
hdfs dfs -chmod g+w /user/hive/warehouse
我们可以在 hive-site.xml 中配置如下信息,便可以实现显示当前数据库以及查询表的头信息:
<property>
<name>hive.cli.print.header</name>
<value>true</value>
</property>
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
</property>
当然我们也可以通过 set 命令来设置:
set hive.cli.print.header=true; # 显示表头
set hive.cli.print.current.db=true; # 显示当前数据库
看下前后的对比:
# 前
hive> select * from studenT;
OK
1 Xiao_ming
2 xiao_hong
3 xiao_hao
Time taken: 0.231 seconds, Fetched: 3 row(s)
# 后
hive (default)> select * from student;
OK
student.id student.name
1 Xiao_ming
2 xiao_hong
3 xiao_hao
Time taken: 0.202 seconds, Fetched: 3 row(s)
可以用 set 查看当前所有参数配置信息:
hive> set
但是一般不这么玩,会显示很多信息。
通常配置文件有三种方式:
上述三种设定方式的优先级依次递增。即配置文件<命令行参数<参数声明。注意某些系统级的参数,例如 log4j 相关的设定,必须用前两种方式设定,因为那些参数的读取在会话建立以前已经完成了。
Hive 数据类型 | Java 数据类型 | 长度 |
---|---|---|
TINYINT | byte | 1 byte 有符号整数 |
SMALINT | short | 2byte 有符号整数 |
INT | int | 4byte 有符号整数 |
BIGINT | long | 8byte 有符号整数 |
BOOLEAN | boolean | 布尔类型,true 或者 false |
FLOAT | float | 单精度浮点数 |
DOUBLE | double | 双精度浮点数 |
STRING | string | 字符系列。可以指定字符集。可以使用单引号或者双引号。 |
TIMESTAMP | 时间类型 | |
BINARY | 字节数组 |
Hive 的 String 类型相当于数据库的 varchar 类型,该类型是一个可变的字符串,不过它不能声明其中最多能存储多少个字符,理论上它可以存储 2GB 的字符数。
数据类型 | 描述 | 语法示例 |
---|---|---|
STRUCT | 和 c 语言中的 struct 类似,都可以通过“点”符号访问元素内容。例如,如果某个列的数据类型是 STRUCT{first STRING, last STRING},那么第 1 个元素可以通过字段.first 来引用。 | struct() |
MAP | MAP 是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是 MAP,其中键->值对 是 ’first’->’John’ 和 ’last’->’Doe’,那么可以通过字段名 [‘last’] 获取最后一个元素。 | map() |
ARRAY | 数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为 [‘John’, ‘Doe’], 那么第 2 个元素可以通过数组名 [1] 进行引用。 | Array() |
Hive 有三种复杂数据类型 ARRAY、MAP、STRUCT。ARRAY 和 MAP 与 Java 中的 Array 和 Map 类似,而 STRUCT 与 C 语言中的 Struct 类似,它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套。
案例实操:
{
"name": "songsong",
"friends": ["bingbing" , "lili"] , //列表 Array,
"children": { //键值 Map,
"xiao song": 18 ,
"xiaoxiao song": 19
},
"address": { //结构 Struct,
"street": "hui long guan" ,
"city": "beijing"
}
}
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
注意:MAP,STRUCT 和 ARRAY 里的元素间关系都可以用同一个字符表示,这里用“_”。
create table test(
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';
字段解释:
hive (default)> load data local inpath '/Users/chenze/Desktop/test.txt' into table test;
先查看下数据:
hive (default)> select * from test;
OK
test.name test.friends test.children test.address
songsong ["bingbing","lili"] {"xiao song":18,"xiaoxiao song":19} {"street":"hui long guan","city":"beijing yangyang"}
Time taken: 0.113 seconds, Fetched: 1 row(s)
查看 ARRAY,MAP,STRUCT 的访问方式:
hive (default)> select friends[1],children['xiao song'],address.city from test where name="songsong";
OK
_c0 _c1 city
lili 18 beijing yangyang
Time taken: 0.527 seconds, Fetched: 1 row(s)
Hive 的原子数据类型是可以进行隐式转换的,类似于 Java 的类型转换,例如某表达式使用 INT 类型,TINYINT 会自动转换为 INT 类型,但是 Hive 不会进行反向转化,例如,某表达式使用 TINYINT 类型,INT 不会自动转换为 TINYINT 类型,它会返回错误,除非使用 CAST 操作。
例如 CAST('1' AS INT) 将把字符串 '1' 转换成整数 1;如果强制类型转换失败,如执行 CAST('X' AS INT),表达式返回空值 NULL。
1、Hive 的存储结构包括「数据库、表、视图、分区和表数据」等。数据库,表,分区等等都对 应 HDFS 上的一个目录。表数据对应 HDFS 对应目录下的文件。
2、Hive 中所有的数据都存储在 HDFS 中,没有专门的数据存储格式,因为 「Hive 是读模式」 (Schema On Read),可支持 TextFile,SequenceFile,RCFile 或者自定义格式等。
3、 只需要在创建表的时候告诉 Hive 数据中的「列分隔符和行分隔符」,Hive 就可以解析数据
4、Hive 中包含以下数据模型:
5、Hive 的元数据存储在 RDBMS 中,除元数据外的其它所有数据都基于 HDFS 存储。默认情 况下,Hive 元数据保存在内嵌的 Derby 数据库中,只能允许一个会话连接,只适合简单的 测试。实际生产环境中不适用,为了支持多用户会话,则需要一个独立的元数据库,使用 MySQL 作为元数据库,Hive 内部对 MySQL 提供了很好的支持。
6、Hive 中的表分为内部表、外部表、分区表和 Bucket 表
使用外部表的场景是针对一个数据集有多个不同的 Schema
通过外部表和内部表的区别和使用选择的对比可以看出来,hive 其实仅仅只是对存储在 HDFS 上的数据提供了一种新的抽象。而不是管理存储在 HDFS 上的数据。所以不管创建内部 表还是外部表,都可以对 hive 表的数据存储目录中的数据进行增删操作。