Hive
hive.apache.org
Hive由Facebook开源,处理海量结构化数据的统计问题。
每一个框架的诞生都是为了去解决一类问题,没有一个框架能兼容所有场景。
对大数据处理,最后落地最好都是SQL实现,受众所有语言的编程人员。而对MapReduce来说需要开发大量代码,因此诞生了Hive。
对于MR来说,就是用于:批计算、离线计算。 ==> Hive 也是。
基于Hadoop
SQL on Hadoop:以SQL 和方式运行在Hadoop上。
- SQL
- UDF
构建在Hadoop之上:
- Hive的数据是存在hdfs
- Hive作业是以MR的方式运行(也可以Hive on Spark)
- Hive作业跑在Yarn上
Hive以类SQL 的语言(Hive QL),可编译为MR作业,提交到Yarn上运行。
- Hive数据:hdfs
默认会将 hive 数据文件放在hdfs “/user/hive/warehouse/” 下
hdfs://Gargantua:9000/user/hive/warehouse
- Hive元数据:MySQL
Hive 底层引擎(不止MR):
- MR
- Tez
- Spark
Hive仅仅是个客户端,只负责将SQL作业翻译为对于引擎作业,再提交到Yarn运行。不需要集群。
Hive SQL 如何运行:
由Driver 完成:
- SQL 解析
- 查询优化
- 物理执行计划
- UDF
- 序列化
- 翻译为对于的作业(MR、Tez、Spark SQL)
MetaStore 元数据
Hive 可以将MetaStore 共享给 Spark SQL、Presto、Impala…
元数据:定义数据的数据。就是一种Schema,存放了数据所在的(表、字段、…)
一般将元数据存在在MySQL(内置是存放在Derby,问题很多,测试都别用);
MySQL 也要部署HA,主备。
Hive 与 RDBS:
- Hive 也支持事务,但对于离线计算每用,重新跑即可。
- Insert、Update 和 Delete 都支持但一般不用。
Hive 部署
https://blog.csdn.net/qq_45494908/article/details/122228034
注意下Hive 与 MySQL 也有版本匹配要求,最低支持MySQL 5.6.17。
整合MySQL的配置文件是在Hive-site.xml。这个文件hive不提供,需要自己在 conf/下添加,driver、url、user、password
[liqiang@Gargantua conf]$ cd /home/liqiang/app/hive/conf
[liqiang@Gargantua conf]$ vi hive-site.xml
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://ip:3306/my_hive?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>账号</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>密码</value>
</property>
Hive目录(app/hive/lib/)添加MySQL驱动包:如mysql-connector-java-5.1.49.jar
初始化Hive元数据到MySQL(不是所有版本都需要做)
配置
日志:
关于log4j.propertities,是放在HIVE_HOME/conf:hive-log4j2.properties,其中配置了运行时日志文件存放的目录和文件名hive.log
property.hive.log.dir = ${sys:java.io.tmpdir}/${sys:user.name}
Hive官网关于Hive配置所有信息
在 WiKi -> Home-> User Documentation -> Hive Configuration Properties
关于hive配置的默认值:
// 控制是否打印查询结果头信息 (是否打印表名)
set hive.cli.print.header; // 查看
set hive.cli.print.header=true; // 临时设置只作用当前session
// 控制是否打印当前数据库名 hive (default)>
hive.cli.print.current.db
// 数据在hdfs 存放的目录
hive.metastore.warehouse.dir=/user/hive/warehouse
设置配置属性
-
set临时设置,只作用当前session
set hive.cli.print.header=true;
-
启动时设置( --hiveconf ),只作用当前session
hive --hiveconf hive.cli.print.current.db=false
-
持久设置:hive-site.xml。
<property> <name>hive.cli.print.header</name> <value>true</value> </property>
优先级:set 临时的配置是可以改掉 xml的设置(约定大于配置)
启动参数
hive -e 可以直接指定sql,直接在linux而不用进入hive就能运行
hive -e "select * from emp;"
hive -f 可以指定一个sql脚本文件,效果同 hive -e。很常用,可以调度。
hive -f pk.sql
// 执行后会回到linux,不启动hive
hive -i 可以指定一个初始化sql来启动Hive
hive -i <filename> Initialization SQL file
// 执行后会启动hive,并留在hive中
Hive的数据组织方式
~~~
database [文件夹]
table [文件夹]
partition [文件夹]
bucket 桶[文件]
~~~
元数据存哪些内容
在MySQL的如下表名中存放对于的元数据:
DATANASE_PARAMS:Hive db的信息
TBLS: Hive表
DBS: 库
COLUMNS_V2:字段信息
...
修复元数据与数据
如操作不当导致元数据信息被删除,即便hdfs上数据还在,也无法通过Hive SQL 查询出。
修复不一致:
msck repair table table_name;
DDL语句
数据定义语言
在 WiKi -> Home-> User Documentation -> DDL
以下只是最常用语句的总结,其他需求可查看官网
database
create database my_db;
// 数据库是在 hdfs : /user/hive/warehouse/my_db
// default 数据库是直接在 /user/hive/warehouse
// 但也可以指定
create database my_db location '/user/hive/warehouse/xxx';
// 列出所有库
show databases;
// 库详细信息 (信息不要轻易改,元数据信息易改漏)
desc database [extanded] my_db;
// 删除库 (库里无表时才能删)
drop database [if exists] my_db;
// 进入库
use my_db;
table
create table [db_name.]table_name (
colnum_name data_type,
...
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' /* 不同列之间的分隔符 (必须ROW FORMAT 开头) */
COMMENT /* 表的注释 */
EXTERNAL /* 是否是外部表,默认true */
COLLECTION ITEMS TERMINGATED BY ',' /* 指列类型为集合时,取值时依赖的分隔符 */
// 增加/修改列
alter table_name ADD|REPLACE colnums (colnum_name data_type)
内/外部表
- 内部表managed: (受Hive管控的),对表做drop操纵时,表和表数据一并删除。
- 外部表external,对表做drop时,只会删除元数据metastore,而表中的数据(存在hdfs上)不会被删除。重新建表仍然可以查原来的数据。多用外部表,防止误操作
- 内部表、外部表转换:
alter table emp set tblproperties("EXTERNAL"="true"); // "EXTERNAL"只支持大写
DML语句
从已存在的表复制(备份)
Inserting data into Hive Tables from queries
// 复制结构+数据新表,新表不能事先存在
create table table_name as select ... ==> CTAS
// 先复制表结构(或本就已存在的表) + insert [overwrite or into] (列的数量/类型要匹配)
create table table_name like table_name;
INSERT OVERWRITE table table_name select * from table_name; // 覆盖
INSERT INTO table table_name select * from table_name; // 追加
// 还能同时将一个表的数据复制到多个表
FROM from_statement INSERT OVERWRITE TABLE tablename select_statement1 FROM from_statement
Load 导入
Loading files into tables
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
# [LOCAL] // 加LOCAL表示从当前linux机器加载,不加LOCAL则是从hdfs
# [OVERWRITE] // 覆盖 or 追加数据
数据导出
Writing data into the filesystem from queries
// 将文件写到本地(从hdfs)
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ]
SELECT ... FROM ...
// 直接hdfs命令将数据拉下来也是一样的效果
hdfs dfs -get /usr/warehouse/db_name/table_name ~/data/
日志数据 ==> 数据清洗ETL ==> 数据仓库 ==》 各种维度的统计分析(SQL) ==> RDBMS ==> 前端(BI报表等)
RDBMS(sqoop、DataX、Spark) ==> 数据仓库 ==》 各种维度的统计分析(SQL) ==> RDBMS ==> 前端(BI报表等)
数据类型
在 WiKi -> Home-> User Documentation -> Data Types
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
Hive03
map<string,string>
// create
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' // 不同列之间的分隔
COLLECTION ITEMS TERMINGATED BY '#' // 指列类型为集合时,取值时依赖的分隔符。类型为:array<string>、map<string,string>...
MAP KEYS TERMINATED BY ':' // 指定map类型 key 与 value之间的分隔
// query
select map_keys[colnum] \ members['key']
分区
分区表也是一个表,但是多了一个分区字段。
分区字段对于hdfs上是一个文件夹
// 按天分区
/usr/warehouse/db/table/day=20220401/...
/usr/warehouse/db/table/day=20220402/...
// 对查询来说,也只是一个字段条件 (多级分区就是两个条件and)
select * from table where day=20220401
静态分区
// create
PARTITIONED BY (col_name data_type, ...) // 多级分区,用逗号分隔
// load
LOAD DATA INPATH 'filepath' INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
// insert
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] ...
静态分区装载数据是需要静态写出分区字段的partcol1=val1,分区较多时不利逐个编写。
动态分区
动态分区不需显示写出分区条件,指定分区字段后去匹配列最后一个字段,执行分区是自动按内容去重分区。(不太适用日期,适用重复性较强的字段)
// creat
create table [db_name.]table_name PARTITION(colnum_name) (
...,
colnum_name data_type
)
严格模式
严格模式下:
- 使用全局排序要求必须加limit
- 对分区表查询,必须带分区where条件
// 关闭严格模式
set hive.exec.dynamic.partition.mode=nonstrict;
// 开启
set hive.exec.dynamic.partition.mode=strict;
分桶 bucket
// create (num_buckets 表示最终桶的个数(文件个数))
CLUSTERED BY (col_name, ...) [SORTED BY (col_name [DESC], ...)] INTO num_buckets BUCKETS
// 是根据分桶字段,用hash运算取模决定存放在哪个桶。(并不是按顺序分桶的)
四个 by
- group by 分组。一般结合聚合函数一起使用。
- order by 全局排序。只使用一个reduce必然性能低,在严格模式下会要求全局排序时必须要加limit。
- sort by 分区排序。只能保证在分区内是有序的,会按rdeuce的个数分区,在一个reduce中排序才能有序,不同reduce不能保证有序。只有一个reduce时分区排==全局排。
// 修改redeuce个数 set mapred.reduce.tasks=3;
- distribute by 只负责数据分发。作用类似MR中的partitioner,指定字段作为分区规则,相同的规则进入同一个reduce。结合 sort by使用时,distribute by 和 sort by 可以是不同字段,也可以是相同字段。
- cluster by 如果 distribute by + sort by是相同字段就可以简写为 cluster by。(不支持手动设置降序)
函数
Operators and User-Defined Functions (UDFs)
在 WiKi -> Home-> User Documentation -> DML(Operators and UDFs)
Build-in
列转行。就是为集合类型的某列数据,查询拆分成多行。
使用split(),拆分成数组后,配合explode栅列函数展开到多行:
select name, c
from teacher_course
lateral view
explode(split(course,',')) tmp as c;
行转列。对单个字段内容的行转列,如分组聚合。(多行多列转换?)
collect_list: 配合group by 将多行数据收集为一个数组
concat_ws: 将多个拼接为一个
UDF
- UDF 一进一出。 如:upper lower substr
- UDAF 多进一出 。 如:sum …
- UDTF 一进多出。 如:explode
自定义UDF函数:https://blog.csdn.net/qq_45494908/article/details/122266503
启动Hive
所以命令都在 HIVE_HOME/bin 目录里
-
hive
就能进入Hive >
退出:hive> quit;// 只启动元数据.默认启动在端口9083。 hive --service metastore hive --service metastore -p 9083 // 不挂断后台启动 nohup hive --service metastore &
-
hiveserver2
简称HS2,启动后作为服务端,接受客户端(beeline、jdbc) 操作
在 WiKi -> Home-> User Documentation -> Hice Clients ==> HiveServer2 -
nohup sh hiveserver2 &
后端启动HS2。不会挂断。(注意不要写成nohub)
(想退出时exit,再关闭shell。直接关闭shell会一直后台运行) -
启动HS2前提下,可以在同目录启动 beeline
% ./beeline beeline> !connect jdbc:hive2://localhost:10000 liqiang // 启动不指定则默认端口10000;密码任意敲 // 进入后可以像在hive> 中一样操作库、表
-
jdbc 连接
启动HS2前提下,可在java客户端连接获取hive数据(是能查hdfs数据,不是metastore元数据)
<dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-jdbc</artifactId> <version>3.1.2</version> </dependency>
官方demo
import java.sql.SQLException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.sql.DriverManager; /** * 从官网https://cwiki.apache.org/confluence/display/Hive/HiveClient#HiveClient-JDBC * * HS2 需要保持打开(不指定则默认端口10000) * * No suitable driver found for jdbc:hive://Gargantua:14000/my_db 改成hive2 * */ public class HiveJdbcClient { // private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver"; // 官网给的有错 private static String driverName = "org.apache.hive.jdbc.HiveDriver"; public static void main(String[] args) throws SQLException { try { Class.forName(driverName); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); System.exit(1); } Connection con = DriverManager.getConnection("jdbc:hive2://Gargantua:10000/my_db", "liqiang", "1"); // 账号为主机名?密码任意 Statement stmt = con.createStatement(); String tableName = "emp_hive"; ResultSet res = stmt.executeQuery("select * from " + tableName); while (res.next()){ System.out.println(res.getInt("empno") + "," + res.getString("ename")); } res.close(); stmt.close(); con.close(); } }
后台程序
前台程序,直接执行 Ctrl+c 就可以终止了。
后台程序,需要先执行exit,再关闭shell。直接关闭shell会一直后台运行。
前台程序转后台程序:Ctrl + z (转后台后,但是是暂停的,需要借助bg命令)
nohup : no hang up(不挂断) 的缩写。不挂断的运行,免疫session的SIGHUP信号。
& :在后台运行,免疫(Ctrl + C)SIGINT信号。
参考:运行查看和关闭后台程序
执行计划
issues
apache所有顶级项目的issues都在:issues.apache.org ==> JIRA
patch:补丁
Hive的解决了的issues是以patch提交。
其他很多开源项目都以 pull request提交到社区。
执行计划三部分
- The Abstract Syntax Tree for the query。AST 抽象语法树(执行计划里已移除)。将SQL字符串翻译成AST ==> MR作业
- The dependencies between the different stages of the plan。MR依赖关系(一条SQL可能有多个MR作业,翻译这个依赖)
- The description of each of the stages。MR 做了什么
reducejoin 和 mapjoin 的执行计划
hive.auto.convert.join 默认为true,代表会自动根据情况将 reducejoin转成mapjoin。
树状层级,从上往下阅读。开头列出了一共使用到达的 几个tage
每一层级会按执行顺序逐次解读SQL Fetch opertor => filter op => join op => select op