一、Hive的基本概念
1、Hive是什么
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
本质是:将HQL转化成MapReduce程序
(1)Hive处理的数据存储在HDFS
(2)Hive分析数据底层的实现是MapReduce
(3)执行程序运行在Yarn上
(4)Hive不是数据库
2、Hive架构
元数据:Metastore
元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore
Hadoop
使用HDFS进行存储,使用MapReduce进行计算。
驱动器:Driver
(1)解析器(SQL Parser):将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。
(2)编译器(Physical Plan):将AST编译生成逻辑执行计划。
(3)优化器(Query Optimizer):对逻辑执行计划进行优化。
(4)执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark。
Hive通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(MetaStore),将这些指令翻译成MapReduce,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口。
Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的。
3、Hive启动脚本
#!/bin/bash
HIVE_LOG_DIR=$HIVE_HOME/logs
if [ ! -d $HIVE_LOG_DIR ]
then
mkdir -p $HIVE_LOG_DIR
fi
#检查进程是否运行正常,参数1为进程名,参数2为进程端口
function check_process()
{
pid=$(ps -ef 2>/dev/null | grep -v grep | grep -i $1 | awk '{print $2}')
ppid=$(netstat -nltp 2>/dev/null | grep $2 | awk '{print $7}' | cut -d '/' -f 1)
echo $pid
[[ "$pid" =~ "$ppid" ]] && [ "$ppid" ] && return 0 || return 1
}
function hive_start()
{
metapid=$(check_process HiveMetastore 9083)
cmd="nohup hive --service metastore >$HIVE_LOG_DIR/metastore.log 2>&1 &"
cmd=$cmd" sleep 4; hdfs dfsadmin -safemode wait >/dev/null 2>&1"
[ -z "$metapid" ] && eval $cmd || echo "Metastroe服务已启动"
server2pid=$(check_process HiveServer2 10000)
cmd="nohup hive --service hiveserver2 >$HIVE_LOG_DIR/hiveServer2.log 2>&1 &"
[ -z "$server2pid" ] && eval $cmd || echo "HiveServer2服务已启动"
}
function hive_stop()
{
metapid=$(check_process HiveMetastore 9083)
[ "$metapid" ] && kill $metapid || echo "Metastore服务未启动"
server2pid=$(check_process HiveServer2 10000)
[ "$server2pid" ] && kill $server2pid || echo "HiveServer2服务未启动"
}
case $1 in
"start")
hive_start
;;
"stop")
hive_stop
;;
"restart")
hive_stop
sleep 2
hive_start
;;
"status")
check_process HiveMetastore 9083 >/dev/null && echo "Metastore服务运行正常" || echo "Metastore服务运行异常"
check_process HiveServer2 10000 >/dev/null && echo "HiveServer2服务运行正常" || echo "HiveServer2服务运行异常"
;;
*)
echo Invalid Args!
echo 'Usage: '$(basename $0)' start|stop|restart|status'
;;
esac
4、Hive和数据库比较
1、写时模式和读时模式
数据库是写时模式,可以对列建立索引,查找数据快;
Hive是读时模式,load data快,不需要读取数据进行解析,仅用于文件的复制和移动
2、数据更新
由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的。而数据库中的数据通常是需要经常进行修改的,
3、执行延迟
Hive 在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致 Hive 执行延迟高的因素是 MapReduce框架。由于MapReduce 本身具有较高的延迟,因此在利用MapReduce 执行Hive查询时,也会有较高的延迟。
4、数据规模
由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。
二、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 good men” |
TIMESTAMP | 时间类型 | ||
BINARY | 字节数组 |
集合数据类型
数据类型 | 描述 | 语法示例 |
---|---|---|
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 |
类型转换
Hive的原子数据类型是可以进行隐式转换的,类似于Java的类型转换,例如某表达式使用INT类型,TINYINT会自动转换为INT类型,但是Hive不会进行反向转化,除非使用CAST操作。
三、DDL数据定义
1、创建数据库
CREATE DATABASE [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path] -- 数据库在HDFS上的默认存储路径是/user/hive/warehouse/*.db
[WITH DBPROPERTIES (property_name=property_value, ...)];
2、查询数据库
显示数据库:show databases;
过滤显示查询的数据库:show databases like ‘db_hive*’;
查看数据库详情:desc database db_hive;或 desc database extended db_hive;
3、删除数据库
drop database db_hive2;
drop database if exists db_hive2;
如果数据库不为空,可以采用cascade命令,强制删除:drop database db_hive cascade;
4、创建表
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] -- eg:row format delimited fields terminated by '\t'。按照‘\t’分隔
[STORED AS file_format] -- 指定存储文件类型 SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)
[LOCATION hdfs_path] -- 指定表在HDFS上的存储位置。
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement] -- 后跟查询语句,根据查询结果创建表。
4.1 管理表
默认创建的表都是所谓的管理表,有时也被称为内部表。因为这种表,Hive会(或多或少地)控制着数据的生命周期。Hive默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。 **当我们删除一个管理表时,Hive也会删除这个表中数据。**管理表不适合和其他工具共享数据。
4.2 外部表(external )
因为表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
查看表格式化数据:desc formatted 表名
4.3 管理表与外部表的互相转换
alter table 表名 set tblproperties('EXTERNAL'='TRUE');
alter table 表名 set tblproperties('EXTERNAL'='FALSE');
四、DML数据操作
1、数据导入
1)向表中装载数据(Load)
load data [local] inpath '数据的path' [overwrite] into table 表名 [partition (partcol1=val1,…)];
local:表示从本地加载数据到hive表;否则从HDFS加载数据到hive表
partition:表示上传到指定分区
2)通过查询语句向表中插入数据(Insert)
eg:
insert overwrite table student
select id, name from student where month='201709';
3)查询语句中创建表并加载数据(As Select)
eg:
-- 根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student3
as select id, name from student;
4)创建表时通过Location指定加载数据路径
create external table if not exists student5(
id int, name string
)
row format delimited fields terminated by '\t'
location '/student; -- 创建表,并指定在hdfs上的位置
5)Import数据到指定Hive表中
import table student2 from
'/user/hive/warehouse/export/student';
-- 注意:先用export导出后,再将数据导入。
2、数据导出
1) Insert导出
-- 将查询的结果格式化导出到本地
insert overwrite local directory '/opt/module/hive/datas/export/student1'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
select * from student;
-- 将查询的结果导出到HDFS上(没有local)
insert overwrite directory '/user/atguigu/student2'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
select * from student;
2)Export导出到HDFS上
export table default.student to
'/user/hive/warehouse/export/student';
五、查询
1、基本查询
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] -- 限制返回的行数
执行顺序:
1st) FROM字句:执行顺序为从后往前、从右到左。数据量较大的表尽量放在后面。
2nd) WHERE字句:执行顺序为自下而上、从右到左。将能过滤掉最大数量记录的条件写在WHERE字句的最右。
3rd) GROUP BY:执行顺序从右往左分组,最好在GROUP BY前使用WHERE将不需要的记录在GROUP BY之前过滤掉
4th) HAVING字句:消耗资源。尽量避免使用,HAVING会在检索出所有记录之后才对结果进行过滤,需要排序等操作。
5th) SELECT字句:少用号,尽量使用字段名称,oracle在解析的过程中,通过查询数据字典将号依次转换成所有列名,消耗时间。
6th) ORDER BY字句:执行顺序从左到右,消耗资源
别名:AS
常用函数:
求总行数(count)
求最大、小值(max、min)
求和:sum
均值:avg
Like和RLike:使用LIKE运算选择类似的值,RLIKE子句是Hive中这个功能的一个扩展,其可以通过Java的正则表达式这个更强大的语言来指定匹配条件。
2、分组
GROUP BY语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。
Having语句
having与where不同点
(1)where后面不能写分组函数,而having后面可以使用分组函数。
(2)having只用于group by分组统计语句。
3、Join
Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接。
3.1 内连接
只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
3.2 左外连接
JOIN操作符左边表中符合WHERE子句的所有记录将会被返回。
3.3 右外连接
JOIN操作符右边表中符合WHERE子句的所有记录将会被返回。
3.4 满外连接
将会返回所有表中符合WHERE语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用NULL值替代。
3.5 多表连接
eg:
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;
连接 n个表,至少需要n-1个连接条件
大多数情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表e和表d进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表l进行连接操作。
优化:当对3个或者更多表进行join连接时,**如果每个on子句都使用相同的连接键的话,**那么只会产生一个MapReduce job。
4、排序
4.1 全局排序
Order By:全局排序,只有一个Reducer
ASC(ascend): 升序(默认)
DESC(descend): 降序
4.2 每个MapReduce内部排序(Sort By)
Sort By:对于大规模的数据集order by的效率非常低。在很多情况下,并不需要全局排序,此时可以使用sort by。
Sort by为每个reducer产生一个排序文件。每个Reducer内部进行排序,对全局结果集来说不是排序。
4.3 分区排序
Distribute By: 在有些情况下,我们需要控制某个特定行应该到哪个reducer,通常是为了进行后续的聚集操作。distribute by 子句可以做这件事。distribute by类似MR中partition(自定义分区),进行分区,结合sort by使用。
对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
eg:先按照部门编号分区,再按照员工编号降序排序。
hive (default)> set mapreduce.job.reduces=3;
hive (default)> insert overwrite local directory '/opt/module/hive/datas/distribute-result' select * from emp distribute by deptno sort by empno desc;
distribute by的分区规则是根据分区字段的hash码与reduce的个数进行模除后,余数相同的分到一个区。
Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
4.4 Cluster By
当distribute by和sorts by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。
六、函数
1、常用内置函数
1.1 空字段赋值
NVL:
格式:NVL( value,default_value)
功能:如果value为NULL,则NVL函数返回default_value的值,否则返回value的值,如果两个参数都为NULL ,则返回NULL。
1.2 CASE WHEN
CASE value WHEN 条件 THEN value1 ELSE value2 END.
eg:
case sex when '男' then 1 else 0 end -- 性别为男 返回1,否则返回0
1.3 行转列
a
b
c ----> a,b,c,d,e 类似于这样的转换称为行转列。
d
e
行转列中常用的函数:
CONCAT(stringA/col, string B/col…):返回输入字符串/列 连接后的结果,支持任意个输入字符串;
CONCAT_WS(separator,str1, str2,…):它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间;CONCAT_WS must be “string or array”
COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。将传入的一列的值,生成一个集合.行转列的主要函数。
GROUP BY:分组函数
1.4 列转行
a
a,b,c —> b 类似于这样的转换称为列转行。
c
列转行中常用的函数:
split() 将指定的字符串按照分隔符组装成一个集合。
EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行。将指定的集合拆分成多行
(炸裂)。主要的列转行函数。因此可以用split函数将列中的数据组装成一个集合。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。侧写函数。
eg:
lateral VIEW
explode(split(列名,",")) tableAlias AS 别名 ; -- 分隔符为逗号
1.5 窗口函数⭐
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。
CURRENT ROW:当前行
n PRECEDING:往前n行数据
n FOLLOWING:往后n行数据
UNBOUNDED:起点,
UNBOUNDED PRECEDING 表示从前面的起点,
UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n,default_val):往前第n行数据
LEAD(col,n, default_val):往后第n行数据
NTILE(n):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。
– 窗口函数: over()
– over() : 默认的窗口大小就是当前整个结果集的大小
– over(partition by 字段) : 在窗口函数中做了分区, 默认的窗口大小就是每个分区的大小.
– 对于每个窗口中的每条数据来讲, 都会开一个窗口。
– over(ORDER BY 字段 ) : 在窗口函数中只用到了order by 排序, 也会对每条数据开一个窗口,
– 默认的窗口大小就是从数据集的开始位置到当前处理的数据的位置。
– 几个关键字总结:
– 建表: partitioned by(分区表) clustered by(分桶)
– 查询: order by(查询中做全局排序) distribute by(查询做分区) sort by(查询做排序) cluster by (查询分区排序)
– 窗口函数: partition by(窗口函数中做分区) order by(窗口函数中做排序)
– distribute by sort by
eg:
数据源:
+----------------+---------------------+----------------+
| business.name | business.orderdate | business.cost |
+----------------+---------------------+----------------+
| jack | 2017-01-01 | 10 |
| tony | 2017-01-02 | 15 |
| jack | 2017-02-03 | 23 |
| tony | 2017-01-04 | 29 |
| jack | 2017-01-05 | 46 |
| jack | 2017-04-06 | 42 |
| tony | 2017-01-07 | 50 |
| jack | 2017-01-08 | 55 |
| mart | 2017-04-08 | 62 |
| mart | 2017-04-09 | 68 |
| neil | 2017-05-10 | 12 |
| mart | 2017-04-11 | 75 |
| neil | 2017-06-12 | 80 |
| mart | 2017-04-13 | 94 |
+----------------+---------------------+----------------+
--(1)查询在2017年4月份购买过的顾客及总人数
SELECT t1.name, COUNT(*) over() -- 这里的count统计的是组的个数
FROM (SELECT NAME ,orderdate, cost
FROM business
WHERE MONTH(orderdate)='04')t1
GROUP BY t1.name
+----------+-----------------+
| t1.name | count_window_0 |
+----------+-----------------+
| jack | 2 |
| mart | 2 |
+----------+-----------------+
--(2)查询每个顾客的购买明细及月购买总额
SELECT NAME, orderdate, cost ,
SUM(cost) over(PARTITION BY NAME ,MONTH(orderdate)) sum_cost -- 对姓名和时间开窗
FROM business
+-------+-------------+-------+-----------+
| NAME | orderdate | cost | sum_cost |
+-------+-------------+-------+-----------+
| jack | 2017-01-01 | 10 | 111 |
| jack | 2017-01-05 | 46 | 111 |
| jack | 2017-01-08 | 55 | 111 |
| jack | 2017-02-03 | 23 | 23 |
| jack | 2017-04-06 | 42 | 42 |
| mart | 2017-04-13 | 94 | 299 |
| mart | 2017-04-08 | 62 | 299 |
| mart | 2017-04-09 | 68 | 299 |
| mart | 2017-04-11 | 75 | 299 |
| neil | 2017-05-10 | 12 | 12 |
| neil | 2017-06-12 | 80 | 80 |
| tony | 2017-01-04 | 29 | 94 |
| tony | 2017-01-07 | 50 | 94 |
| tony | 2017-01-02 | 15 | 94 |
+-------+-------------+-------+-----------+
--(3)上述的场景, 将每个顾客的cost按照日期进行累加
SELECT NAME, orderdate, cost ,
SUM(cost) over( ORDER BY orderdate ) -- 默认窗口大小从数据集开始位置到当前处理数据位置
FROM business
+-------+-------------+-------+---------------+
| NAME | orderdate | cost | sum_window_0 |
+-------+-------------+-------+---------------+
| jack | 2017-01-01 | 10 | 10 |
| tony | 2017-01-02 | 15 | 25 |
| tony | 2017-01-04 | 29 | 54 |
| jack | 2017-01-05 | 46 | 100 |
| tony | 2017-01-07 | 50 | 150 |
| jack | 2017-01-08 | 55 | 205 |
| jack | 2017-02-03 | 23 | 228 |
| jack | 2017-04-06 | 42 | 270 |
| mart | 2017-04-08 | 62 | 332 |
| mart | 2017-04-09 | 68 | 400 |
| mart | 2017-04-11 | 75 | 475 |
| mart | 2017-04-13 | 94 | 569 |
| neil | 2017-05-10 | 12 | 581 |
| neil | 2017-06-12 | 80 | 661 |
+-------+-------------+-------+---------------+
-- 将每个顾客的cost按照日期进行累加
SELECT NAME, orderdate, cost ,
SUM(cost) over(PARTITION BY NAME ORDER BY orderdate) sum_cost
FROM business
+-------+-------------+-------+-----------+
| NAME | orderdate | cost | sum_cost |
+-------+-------------+-------+-----------+
| jack | 2017-01-01 | 10 | 10 |
| jack | 2017-01-05 | 46 | 56 |
| jack | 2017-01-08 | 55 | 111 |
| jack | 2017-02-03 | 23 | 134 |
| jack | 2017-04-06 | 42 | 176 |
| mart | 2017-04-08 | 62 | 62 |
| mart | 2017-04-09 | 68 | 130 |
| mart | 2017-04-11 | 75 | 205 |
| mart | 2017-04-13 | 94 | 299 |
| neil | 2017-05-10 | 12 | 12 |
| neil | 2017-06-12 | 80 | 92 |
| tony | 2017-01-02 | 15 | 15 |
| tony | 2017-01-04 | 29 | 44 |
| tony | 2017-01-07 | 50 | 94 |
+-------+-------------+-------+-----------+
--(4)查询每个顾客上次和下次的购买时间
SELECT NAME, cost , orderdate current_od,
lag(orderdate,1,'1970-01-01') over(distribute BY NAME sort BY orderdate) prev_od , -- 上次
lead(orderdate,1,'9999-01-01') over(distribute BY NAME sort BY orderdate) next_od -- 下次
FROM business
+-------+-------+-------------+-------------+-------------+
| NAME | cost | current_od | prev_od | next_od |
+-------+-------+-------------+-------------+-------------+
| jack | 10 | 2017-01-01 | 1970-01-01 | 2017-01-05 |
| jack | 46 | 2017-01-05 | 2017-01-01 | 2017-01-08 |
| jack | 55 | 2017-01-08 | 2017-01-05 | 2017-02-03 |
| jack | 23 | 2017-02-03 | 2017-01-08 | 2017-04-06 |
| jack | 42 | 2017-04-06 | 2017-02-03 | 9999-01-01 |
| mart | 62 | 2017-04-08 | 1970-01-01 | 2017-04-09 |
| mart | 68 | 2017-04-09 | 2017-04-08 | 2017-04-11 |
| mart | 75 | 2017-04-11 | 2017-04-09 | 2017-04-13 |
| mart | 94 | 2017-04-13 | 2017-04-11 | 9999-01-01 |
| neil | 12 | 2017-05-10 | 1970-01-01 | 2017-06-12 |
| neil | 80 | 2017-06-12 | 2017-05-10 | 9999-01-01 |
| tony | 15 | 2017-01-02 | 1970-01-01 | 2017-01-04 |
| tony | 29 | 2017-01-04 | 2017-01-02 | 2017-01-07 |
| tony | 50 | 2017-01-07 | 2017-01-04 | 9999-01-01 |
+-------+-------+-------------+-------------+-------------+
--(5)查询前20%时间的订单信息
SELECT t1.name, t1.orderdate, t1.cost ,t1.gid
FROM
(
SELECT NAME, orderdate, cost ,
ntile(5) over(ORDER BY orderdate) gid -- ntile 将数据分为5份
FROM business
) t1
WHERE t1.gid = 1
+----------+---------------+----------+---------+
| t1.name | t1.orderdate | t1.cost | t1.gid |
+----------+---------------+----------+---------+
| jack | 2017-01-01 | 10 | 1 |
| tony | 2017-01-02 | 15 | 1 |
| tony | 2017-01-04 | 29 | 1 |
+----------+---------------+----------+---------+
1.6 Rank函数
RANK() 排序相同时会重复,总数不会变
DENSE_RANK() 排序相同时会重复,总数会减少
ROW_NUMBER() 会根据顺序计算
1.7 其他常用函数
常用日期函数
unix_timestamp:返回当前或指定时间的时间戳
from_unixtime:将时间戳转为日期格式
current_date:当前日期
current_timestamp:当前的日期加时间
to_date:抽取日期部分
year:获取年
month:获取月
day:获取日
hour:获取时
minute:获取分
second:获取秒
weekofyear:当前时间是一年中的第几周
dayofmonth:当前时间是一个月中的第几天
months_between: 两个日期间的月份
add_months:日期加减月
datediff:两个日期相差的天数
date_add:日期加天数
date_sub:日期减天数
last_day:日期的当月的最后一天
常用取整函数
round: 四舍五入
ceil: 向上取整
floor: 向下取整
常用字符串操作函数
upper: 转大写
lower: 转小写
length: 长度
trim: 前后去空格
lpad: 向左补齐,到指定长度
rpad: 向右补齐,到指定长度
regexp_replace: SELECT regexp_replace('100-200', '(\\d+)', 'num') ;
使用正则表达式匹配目标字符串,匹配成功后替换!
集合操作
size: 集合中元素的个数
map_keys: 返回map中的key
map_values: 返回map中的value
array_contains: 判断array中是否包含某个元素
sort_array: 将array中的元素排序
七、分区表和分桶表
1、分区表
分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。**Hive中的分区就是分目录,**把一个大的数据集根据业务需要分割成小的数据集。在查询时通过WHERE子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
基本语法:
eg:
create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (day string) //按天分区
row format delimited fields terminated by '\t';
分区字段不能是表中已经存在的数据,可以将分区字段看作表的伪列。
注意:分区表加载数据时,必须指定分区
eg:
load data local inpath '/opt/module/hive/datas/dept_20200401.log' into table dept_partition partition(day='20200401');
增加分区:eg:
alter table dept_partition add partition(day='20200405') partition(day='20200406');
删除分区:
alter table dept_partition drop partition (day='20200404'), partition(day='20200405');
查看分区表结构:
desc formatted dept_partition;
创建二级分区:
create table dept_partition2(
deptno int, dname string, loc string
)
partitioned by (day string, hour string)
row format delimited fields terminated by '\t';
把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式
方式一:上传数据后修复:
msck repair table dept_partition2; //修复命令
方式二:上传数据后添加分区
方式三:创建文件夹后load数据到分区
也可以创建动态分区,根据分区字段,自动将数据添加至相应的分区。
2、分桶
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分。
分桶是将数据集分解成更容易管理的若干部分的另一个技术。
分区针对的是数据的存储路径;分桶针对的是数据文件。
创建分桶表:
create table stu_buck(id int, name string)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
分桶规则:
Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中
八、补充
1、数据仓库多维度数据模型
- 星型模型:事实表在中心,周围围绕连接维表(每维一个),事实表包含大量数据,冗余度高。
- 雪花模型:星型模型的变种,其中某些维表是规范化的,因而把数据进一步分解到附加表中,结果模型类似于雪花,冗余度低。
- 事实星座模型或星系模型:包含多个事实表,而维表是公开的,可以共享。
2、严格模式:
Hive可以通过设置防止一些危险操作:
(1)将hive.strict.checks.no.partition.filter设置为true时,对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
(2)将hive.strict.checks.orderby.no.limit设置为true时,**对于使用了order by语句的查询,要求必须使用limit语句。**因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
(3)将hive.strict.checks.cartesian.product设置为true时,会限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在 执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。
放在哪个桶当中
八、补充
1、数据仓库多维度数据模型
- 星型模型:事实表在中心,周围围绕连接维表(每维一个),事实表包含大量数据,冗余度高。
- 雪花模型:星型模型的变种,其中某些维表是规范化的,因而把数据进一步分解到附加表中,结果模型类似于雪花,冗余度低。
- 事实星座模型或星系模型:包含多个事实表,而维表是公开的,可以共享。
2、严格模式:
Hive可以通过设置防止一些危险操作:
(1)将hive.strict.checks.no.partition.filter设置为true时,对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
(2)将hive.strict.checks.orderby.no.limit设置为true时,**对于使用了order by语句的查询,要求必须使用limit语句。**因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
(3)将hive.strict.checks.cartesian.product设置为true时,会限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在 执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。