其他更多java基础文章:
java基础学习(目录)
Hive基本概念
Hive 的优缺点
优点
- 操作接口采用类 SQL 语法,提供快速开发的能力(简单、容易上手) 。
- 避免了去写 MapReduce,减少开发人员的学习成本。
- Hive 的执行延迟比较高,因此 Hive 常用于数据分析,对实时性要求不高的场合。
- Hive 优势在于处理大数据,对于处理小数据没有优势,因为 Hive 的执行延迟比较
高。
5. Hive 支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
缺点
- Hive 的 HQL 表达能力有限
- 迭代式算法无法表达
- 数据挖掘方面不擅长, 由于 MapReduce 数据处理流程的限制,效率更高的算法却无法实现。
- Hive 的效率比较低
- Hive 自动生成的 MapReduce 作业,通常情况下不够智能化
- Hive 调优比较困难,粒度较粗
Hive架构原理
用户接口: Client
CLI(command-line interface)、 JDBC/ODBC(jdbc 访问 hive)、 WEBUI(浏览器访问 hive)
元数据: Metastore
元数据包括:表名、表所属的数据库(默认是 default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
默认存储在自带的 derby 数据库中,推荐使用 MySQL 存储 Metastore
Hadoop/Spark
使用 HDFS 进行存储,使用 MapReduce 进行计算。
驱动器: Driver
- 解析器(SQL Parser):将 SQL 字符串转换成抽象语法树 AST,这一步一般都用第三方工具库完成,比如 antlr;对 AST 进行语法分析,比如表是否存在、字段是否存在、 SQL语义是否有误。
- 编译器(Physical Plan):将 AST 编译生成逻辑执行计划。
- 优化器(Query Optimizer):对逻辑执行计划进行优化。
- 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于 Hive 来说, 就是 MR/Spark。
Hive 通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的 Driver,结合元数据(MetaStore),将这些指令翻译成 MapReduce,提交到 Hadoop/Spark 中执行,最后,将执行返回的结果输出到用户交互接口。
Hive数据类型
基本数据类型
Hive 数据类型 | Java 数据类型 | 长度 | 例子 |
---|---|---|---|
TINYINT | byte | 1byte 有符号整数 | 20 |
SMALINT | short | 2byte 有符号整数 | 20 |
INT | int | 4byte 有符号整数 | 20 |
BIGINT | long | 8byte 有符号整数 | 20 |
BOOLEAN | boolean | 布尔类型, true 或者false | TRUE FALSE |
FLOAT | float | 单精度浮点数 | 3.14159 |
DOUBLE | double | 双精度浮点数 | 3.14159 |
STRING | string | 字符系列。可以指定字符集。可以使用单引号或者双引号。 | ‘now is the time ’ “for all ood men” |
TIMESTAMP | 时间类型 | ||
BINARY | 字节数组 |
对于 Hive 的 String 类型相当于数据库的 varchar 类型,该类型是一个可变的字符串,不
过它不能声明其中最多能存储多少个字符,理论上它可以存储 2GB 的字符数。
集合数据类型
数据类型 | 描述 | 语法示例 |
---|---|---|
STRUCT | 和 c 语言中的 struct 类似,都可以通过“点”符号访问元素内容。例如,如果某个列的数据类型是 STRUCT{first STRING, last STRING},那么第 1 个元素可以通过字段.first 来引用。 | struct() 例如: struct<street:string,city:string> |
MAP | MAP 是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是 MAP,其中键->值对是’ first’ ->’ John’和’ last’ ->’ Doe’,那么可以通过字段名[‘last’ ]获取最后一个元素 | map() 例如: map<string, int> |
ARRAY | 数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为[‘John’ , ‘Doe’ ],那么第 2 个元素可以通过数组名[1]进行引用。 | Array() 例如 array<string> |
Hive 有三种复杂数据类型 ARRAY、 MAP 和 STRUCT。 ARRAY 和 MAP 与 Java 中的 Array和 Map 类似,而 STRUCT 与 C 语言中的 Struct 类似(或者java的对象),它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套。
案例实操
- 假设某表有如下一行, 我们用 JSON 格式来表示其数据结构。在 Hive 下访问的格
式为
{
"name": "songsong",
"friends": ["bingbing" , "lili"] , //列表 Array,
"children": { //键值 Map,
"xiao song": 18 ,
"xiaoxiao song": 19
}
"address": { //结构 Struct,
"street": "hui long guan",
"city": "beijing"
}
}
复制代码
- 基于上述数据结构, 我们在 Hive 里创建对应的表, 并导入数据。
创建本地测试文件 test.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
复制代码
注意: MAP, STRUCT 和 ARRAY 里的元素间关系都可以用同一个字符表示, 这里用“_”。
- Hive 上创建测试表 test
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';
复制代码
字段解释:
row format delimited fields terminated by ‘,’ — 列分隔符
collection items terminated by ‘_’ –MAP STRUCT 和 ARRAY 的分隔符(数据分割符号)
map keys terminated by ‘:’ — MAP 中的 key 与 value 的分隔符
lines terminated by ‘\n’; — 行分隔符
- 导入文本数据到测试表
load data local inpath '/opt/module/hive/datas/test.txt' into table test;
复制代码
- 访问三种集合列里的数据,以下分别是 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
Time taken: 0.076 seconds, Fetched: 1 row(s)
复制代码
DDL 数据定义
创建表
建表语法
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]
复制代码
字段解释说明
- CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在, 则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
- EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径(LOCATION),在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
- COMMENT:为表和列添加注释。
- PARTITIONED BY 创建分区表
- CLUSTERED BY 创建分桶表
- SORTED BY 不常用, 对桶中的一个或多个列另外排序
- ROW FORMAT
ROW FORMAT DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)]
row format delimited fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';
复制代码
用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROWFORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe, Hive 通过 SerDe 确定表的具体的列的数据。
SerDe 是 Serialize/Deserilize 的简称, hive 使用 Serde 进行行对象的序列与反序列化。
- STORED AS 指定存储文件类型 常用的存储文件类型: SEQUENCEFILE(二进制序列文件)、 TEXTFILE(文本)、 RCFILE(列式存储格式文件)。如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
- LOCATION :指定表在 HDFS 上的存储位置。
- AS:后跟查询语句, 根据查询结果创建表。
- LIKE 允许用户复制现有的表结构,但是不复制数据。
示例
(1)普通创建表
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)根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student2 as select id, name from student;
复制代码
(3)根据已经存在的表结构创建表
create table if not exists student3 like student;
复制代码
DML 数据操作
数据导入
向表中装载数据(Load)
语法
hive> load data [local] inpath '数据的path' [overwrite] into table
student [partition (partcol1=val1,…)];
复制代码
- load data:表示加载数据
- local:表示从本地加载数据到 hive 表; 否则从 HDFS 加载数据到 hive 表
- inpath:表示加载数据的路径
- overwrite:表示覆盖表中已有数据,否则表示追加
- into table:表示加载到哪张表
- student:表示具体的表
- partition:表示上传到指定分区
实操案例
(0) 创建一张表
hive (default)> create table student(id string, name string) row format delimited fields terminated by '\t';
复制代码
(1) 加载本地文件到 hive
hive (default)> load data local inpath '/opt/module/hive/datas/student.txt' into table default.student;
复制代码
(2) 加载 HDFS 文件到 hive 中
上传文件到 HDFS
hive (default)> dfs -put /opt/module/hive/data/student.txt /user/atguigu/hive;
复制代码
加载 HDFS 上数据
hive (default)> load data inpath '/user/atguigu/hive/student.txt' into table default.student;
复制代码
(3) 加载数据覆盖表中已有的数据
hive (default)> load data inpath '/user/atguigu/hive/student.txt'
overwrite into table default.student;
复制代码
通过查询语句向表中插入数据(Insert)
基本插入数据
hive (default)> insert into table student_par values(1,'wangwu'),(2,'zhaoliu');
复制代码
基本模式插入(根据单张表查询结果)
hive (default)> insert overwrite table student_par select id, name from student where month='201709';
复制代码
insert into: 以追加数据的方式插入到表或分区, 原有数据不会删除
insert overwrite: 会覆盖表中已存在的数据
注意: insert 不支持插入部分字段
多表(多分区) 插入模式(根据多张表查询结果)
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';
复制代码
创建表时通过 Location 指定加载数据路径
hive (default)> create external table if not exists student5(
id int, name string
)
row format delimited fields terminated by '\t'
location '/student;
复制代码
数据导出
将查询的结果导出到本地
hive (default)> insert overwrite local directory '/opt/module/hive/data/export/student' select * from student;
复制代码
将查询的结果格式化导出到本地
hive(default)>insert overwrite local directory '/opt/module/hive/data/export/student1'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
复制代码
将查询的结果导出到 HDFS 上(没有 local)
hive (default)> insert overwrite directory '/user/atguigu/student2'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
复制代码
查询
基本查询
查询语句语法:
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]
复制代码
注意:
(1) SQL 语言大小写不敏感。
(2) SQL 可以写在一行或者多行
(3)关键字不能被缩写也不能分行
(4)各子句一般要分行写。
(5)使用缩进提高语句的可读性。
Like 和 RLike
- % 代表零个或多个字符(任意个字符)。
- _ 代表一个字符。
RLIKE 子句
RLIKE 子句是 Hive 中这个功能的一个扩展,其可以通过 Java 的正则表达式这个更强大的语言来指定匹配条件
案例实操
(1)查找名字以 A 开头的员工信息
hive (default)> select * from emp where ename LIKE 'A%';
复制代码
(2)查找名字中第二个字母为 A 的员工信息
hive (default)> select * from emp where ename LIKE '_A%';
复制代码
(3)查找名字中带有 A 的员工信息
hive (default)> select * from emp where ename RLIKE '[A]';
复制代码
Having 语句
having 与 where 不同点:
(1) where 后面不能写分组函数, 而 having 后面可以使用分组函数。
(2) having 只用于 group by 分组统计语句。
多表连接查询
hive (default)>SELECT e.ename, d.dname, l.loc_name
FROM emp e
JOIN dept d
ON d.deptno = e.deptno
JOIN location l
ON d.loc = l.loc;
复制代码
大多数情况下, Hive 会对每对 JOIN 连接对象启动一个 MapReduce 任务。本例中会首先启动一个 MapReduce job 对表 e 和表 d 进行连接操作,然后会再启动一个 MapReduce job 将第一个 MapReduce job 的输出和表 l;进行连接操作。
注意:为什么不是表 d 和表 l 先进行连接操作呢?这是因为 Hive 总是按照从左到右的顺序执行的。
优化: 当对 3 个或者更多表进行 join 连接时,如果每个 on 子句都使用相同的连接键的话,那么只会产生一个 MapReduce job。
排序
全局排序(Order By)
Order By: 全局排序, 只有一个 Reducer
每个 Reduce 内部排序(Sort By)
Sort By: 对于大规模的数据集 order by 的效率非常低。在很多情况下, 并不需要全局排序, 此时可以使用 sort by。
Sort by 为每个 reducer 产生一个排序文件。 每个 Reducer 内部进行排序, 对全局结果集来说不是排序。
- 设置 reduce 个数
hive (default)> set mapreduce.job.reduces=3;
复制代码
- 查看设置 reduce 个数
hive (default)> set mapreduce.job.reduces;
复制代码
- 根据部门编号降序查看员工信息
hive (default)> select * from emp sort by deptno desc;
复制代码
- 将查询结果导入到文件中(按照部门编号降序排序)
hive (default)> insert overwrite local directory '/opt/module/data/sortby-result'
select * from emp sort by deptno desc;
复制代码
分区(Distribute By)
Distribute By: 在有些情况下, 我们需要控制某个特定行应该到哪个 reducer, 通常是为了进行后续的聚集操作。 distribute by 子句可以做这件事。 distribute by 类似 MR 中 partition(自定义分区) ,进行分区,结合 sort by 使用。
对于 distribute by 进行测试,一定要分配多 reduce 进行处理,否则无法看到 distribute by 的效果。
案例实操:
先按照部门编号分区,再按照员工编号降序排序。
hive (default)> set mapreduce.job.reduces=3;
hive (default)> insert overwrite local directory
'/opt/module/data/distribute-result' select * from emp distribute by
deptno sort by empno desc;
复制代码
注意:
- distribute by 的分区规则是根据分区字段的 hash 码与 reduce 的个数进行模除后,余数相同的分到一个区。
- Hive 要求 DISTRIBUTE BY 语句要写在 SORT BY 语句之前。
Cluster By
当 distribute by 和 sorts by 字段相同时,可以使用 cluster by 方式。
cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能。但是排序只能是升序排序, 不能指定排序规则为 ASC 或者 DESC。
以下两种写法等价:
hive (default)> select * from emp cluster by deptno;
hive (default)> select * from emp distribute by deptno sort by deptno;
复制代码
分区表和分桶表
分区表
分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。 Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
分区表基本操作
创建分区表语法
hive (default)> create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (day string)
row format delimited fields terminated by '\t';
复制代码
注意:分区字段不能是表中已经存在的数据,可以将分区字段看作表的伪列。
加载数据
hive (default)> load data local inpath
'/opt/module/hive/datas/dept_20200401.log' into table dept_partition
partition(day='20200401');
hive (default)> load data local inpath
'/opt/module/hive/datas/dept_20200402.log' into table dept_partition
partition(day='20200402');
hive (default)> load data local inpath
'/opt/module/hive/datas/dept_20200403.log' into table dept_partition
partition(day='20200403');
复制代码
查询分区表中数据
单分区查询
hive (default)> select * from dept_partition where day='20200401';
多分区联合查询
hive (default)> select * from dept_partition where day='20200401'
union
select * from dept_partition where day='20200402'
union
select * from dept_partition where day='20200403';
hive (default)> select * from dept_partition where day='20200401' or day='20200402' or day='20200403';
复制代码
增加分区
创建单个分区
hive (default)> alter table dept_partition add partition(day='20200404');
同时创建多个分区
hive (default)> alter table dept_partition add partition(day='20200405')
partition(day='20200406');
复制代码
删除分区
删除单个分区
hive (default)> alter table dept_partition drop partition
(day='20200406');
同时删除多个分区
hive (default)> alter table dept_partition drop partition
(day='20200404'), partition(day='20200405');
复制代码
查看分区表有多少分区
hive> show partitions dept_partition;
复制代码
二级分区
创建二级分区表
hive (default)> create table dept_partition2(
deptno int, dname string, loc string
)
partitioned by (day string, hour string)
row format delimited fields terminated by '\t';
复制代码
正常的加载数据
(1)加载数据到二级分区表中
hive (default)> load data local inpath
'/opt/module/hive/datas/dept_20200401.log' into table
dept_partition2 partition(day='20200401', hour='12');
复制代码
(2) 查询分区数据
hive (default)> select * from dept_partition2 where day='20200401' and
hour='12';
复制代码
把数据直接上传到分区目录上, 让分区表和数据产生关联的三种方式
方式一:上传数据后修复
上传数据
hive (default)> dfs -mkdir -p
/user/hive/warehouse/mydb.db/dept_partition2/day=20200401/hour=13;
hive (default)> dfs -put /opt/module/datas/dept_20200401.log
/user/hive/warehouse/mydb.db/dept_partition2/day=20200401/hour=13;
复制代码
查询数据(查询不到刚上传的数据)
hive (default)> select * from dept_partition2 where day='20200401' and
hour='13';
复制代码
执行修复命令
hive> msck repair table dept_partition2;
复制代码
再次查询数据
hive (default)> select * from dept_partition2 where day='20200401' and
hour='13';
复制代码
方式二:上传数据后添加分区
上传数据
hive (default)> dfs -mkdir -p
/user/hive/warehouse/mydb.db/dept_partition2/day=20200401/hour=14;
hive (default)> dfs -put /opt/module/hive/datas/dept_20200401.log
/user/hive/warehouse/mydb.db/dept_partition2/day=20200401/hour=14;
复制代码
执行添加分区
hive (default)> alter table dept_partition2 add
partition(day='201709',hour='14');
复制代码
查询数据
hive (default)> select * from dept_partition2 where day='20200401' and
hour='14';
复制代码
方式三: 创建文件夹后 load 数据到分区
创建目录
hive (default)> dfs -mkdir -p
/user/hive/warehouse/mydb.db/dept_partition2/day=20200401/hour=15;
复制代码
上传数据
hive (default)> load data local inpath
'/opt/module/hive/datas/dept_20200401.log' into table
dept_partition2 partition(day='20200401',hour='15');
复制代码
查询数据
hive (default)> select * from dept_partition2 where day='20200401' and
hour='15';
复制代码
动态分区调整
关系型数据库中, 对分区表 Insert 数据时候, 数据库自动会根据分区字段的值, 将数据插入到相应的分区中, Hive 中也提供了类似的机制, 即动态分区(Dynamic Partition), 只不过,使用 Hive 的动态分区, 需要进行相应的配置。
开启动态分区参数设置
(1)开启动态分区功能(默认 true,开启)
hive.exec.dynamic.partition=true
复制代码
(2)设置为非严格模式(动态分区的模式,默认 strict,表示必须指定至少一个分区为静态分区, nonstrict 模式表示允许所有的分区字段都可以使用动态分区。)
hive.exec.dynamic.partition.mode=nonstrict
复制代码
(3)在所有执行 MR 的节点上,最大一共可以创建多少个动态分区。默认 1000
hive.exec.max.dynamic.partitions=1000
复制代码
(4) 在每个执行 MR 的节点上,最大可以创建多少个动态分区。 该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即 day 字段有 365 个值,那么该参数就需要设置成大于 365,如果使用默认值 100,则会报错。
hive.exec.max.dynamic.partitions.pernode=100
复制代码
(5)整个 MR Job 中,最大可以创建多少个 HDFS 文件。默认 100000
hive.exec.max.created.files=100000
复制代码
(6)当有空分区生成时,是否抛出异常。一般不需要设置。默认 false
hive.error.on.empty.partition=false
复制代码
案例实操
需求: 将 dept 表中的数据按照地区(loc 字段), 插入到目标表 dept_partition 的相应分区中。
(1) 创建目标分区表
hive (default)> create table dept_partition_dy(id int, name string)
partitioned by (loc int) row format delimited fields terminated by '\t';
复制代码
(2) 设置动态分区
set hive.exec.dynamic.partition.mode = nonstrict;
hive (default)> insert into table dept_partition_dy partition(loc) select
deptno, dname, loc from dept;
复制代码
(3) 查看目标分区表的分区情况
hive (default)> show partitions dept_partition;
复制代码