您的位置:首页 > 游戏 > 游戏 > 掌握Hive函数[3]:从基础到高级应用

掌握Hive函数[3]:从基础到高级应用

2024/10/6 6:40:39 来源:https://blog.csdn.net/qq_45115959/article/details/142030367  浏览:    关键词:掌握Hive函数[3]:从基础到高级应用

目录

窗口函数(开窗函数)

 概述

 常用窗口函数

1)聚合函数

2)跨行取值函数

(1)LEAD 和 LAG

(2)FIRST_VALUE 和 LAST_VALUE

3)排名函数

 案例演示

1. 数据准备

1)表结构

2)建表语句

3)装载语句

2. 需求

1)统计每个用户截至每次下单的累积下单总额

(1)期望结果

(2)需求实现

2)统计每个用户截至每次下单的当月累积下单总额

(1)期望结果

(2)需求实现

3)统计每个用户每次下单距离上次下单相隔的天数(首次下单按0天算)

(1)期望结果

(2)需求实现

4)查询所有下单记录以及每个用户的每个下单记录所在月份的首/末次下单日期

(1)期望结果

(2)需求实现

5)为每个用户的所有下单记录按照订单金额进行排名

(1)期望结果

(2)需求实现

 自定义函数

自定义UDF函数


窗口函数(开窗函数)

 概述

窗口函数是一种在SQL中处理数据的强大工具,它允许用户在结果集的一个特定窗口或范围内执行计算,而不是在整个查询结果上进行操作。

 常用窗口函数

按照功能,常用窗口函数可以划分为以下几类:聚合函数、跨行取值函数、排名函数。

1)聚合函数
  • MAX:最大值。
  • MIN:最小值。
  • SUM:求和。
  • AVG:平均值。
  • COUNT:计数。
2)跨行取值函数
(1)LEAD 和 LAG
  • LEAD:向前查看,即获取当前行之后的某一行的值。
  • LAG:向后查看,即获取当前行之前的一行的值。

 

(2)FIRST_VALUE 和 LAST_VALUE
  • FIRST_VALUE:返回窗口中第一个行的表达式的值。
  • LAST_VALUE:返回窗口中最后一个行的表达式的值。

 

3)排名函数
  • RANK:根据一个或多个列的值对行进行排序,并跳过中间的空位。
  • DENSE_RANK:与 RANK 类似,但是不会跳过任何排名。
  • ROW_NUMBER:给每一行分配一个唯一的整数。

 案例演示

1. 数据准备
1)表结构
order_iduser_iduser_nameorder_dateorder_amount
11001小元2022-01-0110
21002小海2022-01-0215
31001小元2022-02-0323
41002小海2022-01-0429
51001小元2022-01-0546
61001小元2022-04-0642
71002小海2022-01-0750
81001小元2022-01-0850
91003小辉2022-04-0862
101003小辉2022-04-0962
111004小猛2022-05-1012
121003小辉2022-04-1175
131004小猛2022-06-1280
141003小辉2022-04-1394
2)建表语句
CREATE TABLE order_info (order_id   STRING, --订单iduser_id    STRING, -- 用户iduser_name  STRING, -- 用户姓名order_date STRING, -- 下单日期order_amount INT    -- 订单金额
);
3)装载语句
INSERT OVERWRITE TABLE order_info
VALUES 
('1', '1001', '小元', '2022-01-01', '10'),
('2', '1002', '小海', '2022-01-02', '15'),
('3', '1001', '小元', '2022-02-03', '23'),
('4', '1002', '小海', '2022-01-04', '29'),
('5', '1001', '小元', '2022-01-05', '46'),
('6', '1001', '小元', '2022-04-06', '42'),
('7', '1002', '小海', '2022-01-07', '50'),
('8', '1001', '小元', '2022-01-08', '50'),
('9', '1003', '小辉', '2022-04-08', '62'),
('10', '1003', '小辉', '2022-04-09', '62'),
('11', '1004', '小猛', '2022-05-10', '12'),
('12', '1003', '小辉', '2022-04-11', '75'),
('13', '1004', '小猛', '2022-06-12', '80'),
('14', '1003', '小辉', '2022-04-13', '94');
2. 需求
1)统计每个用户截至每次下单的累积下单总额
(1)期望结果
order_iduser_iduser_nameorder_dateorder_amountsum_so_far
11001小元2022-01-011010
51001小元2022-01-054656
81001小元2022-01-0850106
31001小元2022-02-0323129
61001小元2022-04-0642171
21002小海2022-01-021515
41002小海2022-01-042944
71002小海2022-01-075094
91003小辉2022-04-086262
101003小辉2022-04-0962124
121003小辉2022-04-1175199
141003小辉2022-04-1394293
111004小猛2022-05-101212
131004小猛2022-06-128092
(2)需求实现
SELECTorder_id,user_id,user_name,order_date,order_amount,SUM(order_amount) OVER (PARTITION BY user_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum_so_far
FROM order_info;
2)统计每个用户截至每次下单的当月累积下单总额
(1)期望结果
order_iduser_iduser_nameorder_dateorder_amountsum_so_far
11001小元2022-01-011010
51001小元2022-01-054656
81001小元2022-01-0850106
31001小元2022-02-032323
61001小元2022-04-064242
21002小海2022-01-021515
41002小海2022-01-042944
71002小海2022-01-075094
91003小辉2022-04-086262
101003小辉2022-04-0962124
121003小辉2022-04-1175199
141003小辉2022-04-1394293
111004小猛2022-05-101212
131004小猛2022-06-128080
(2)需求实现
SELECTorder_id,user_id,user_name,order_date,order_amount,SUM(order_amount) OVER (PARTITION BY user_id, SUBSTRING(order_date, 1, 7) ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum_so_far
FROM order_info;
3)统计每个用户每次下单距离上次下单相隔的天数(首次下单按0天算)
(1)期望结果
order_iduser_iduser_nameorder_dateorder_amountdiff
11001小元2022-01-01100
51001小元2022-01-05464
81001小元2022-01-08503
31001小元2022-02-032326
61001小元2022-04-064262
21002小海2022-01-02150
41002小海2022-01-04292
71002小海2022-01-07503
91003小辉2022-04-08620
101003小辉2022-04-09621
121003小辉2022-04-11752
141003小辉2022-04-13942
111004小猛2022-05-10120
131004小猛2022-06-128033
(2)需求实现
SELECTorder_id,user_id,user_name,order_date,order_amount,NVL(DATEDIFF(order_date, last_order_date), 0) diff
FROM
(SELECTorder_id,user_id,user_name,order_date,order_amount,LAG(order_date, 1, NULL) OVER (PARTITION BY user_id ORDER BY order_date) last_order_dateFROM order_info
) t1;
4)查询所有下单记录以及每个用户的每个下单记录所在月份的首/末次下单日期
(1)期望结果
order_iduser_iduser_nameorder_dateorder_amountfirst_datelast_date
11001小元2022-01-01102022-01-012022-01-08
51001小元2022-01-05462022-01-012022-01-08
81001小元2022-01-08502022-01-012022-01-08
31001小元2022-02-03232022-02-032022-02-03
61001小元2022-04-06422022-04-062022-04-06
21002小海2022-01-02152022-01-022022-01-07
41002小海2022-01-04292022-01-022022-01-07
71002小海2022-01-07502022-01-022022-01-07
91003小辉2022-04-08622022-04-082022-04-13
101003小辉2022-04-09622022-04-082022-04-13
121003小辉2022-04-11752022-04-082022-04-13
141003小辉2022-04-13942022-04-082022-04-13
111004小猛2022-05-10122022-05-102022-05-10
131004小猛2022-06-12802022-06-122022-06-12
(2)需求实现
SELECTorder_id,user_id,user_name,order_date,order_amount,FIRST_VALUE(order_date) OVER (PARTITION BY user_id, SUBSTRING(order_date, 1, 7) ORDER BY order_date) first_date,LAST_VALUE(order_date) OVER (PARTITION BY user_id, SUBSTRING(order_date, 1, 7) ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_date
FROM order_info;
5)为每个用户的所有下单记录按照订单金额进行排名
(1)期望结果
order_iduser_iduser_nameorder_dateorder_amountrkdrkrn
81001小元2022-01-0850111
51001小元2022-01-0546222
61001小元2022-04-0642333
31001小元2022-02-0323444
11001小元2022-01-0110555
71002小海2022-01-0750111
41002小海2022-01-0429222
21002小海2022-01-0215333
141003小辉2022-04-1394111
121003小辉2022-04-1175222
91003小辉2022-04-0862333
101003小辉2022-04-0962334
131004小猛2022-06-1280111
111004小猛2022-05-1012222
(2)需求实现
SELECTorder_id,user_id,user_name,order_date,order_amount,RANK() OVER (PARTITION BY user_id ORDER BY order_amount DESC) rk,DENSE_RANK() OVER (PARTITION BY user_id ORDER BY order_amount DESC) drk,ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_amount DESC) rn
FROM order_info;

 自定义函数

1)Hive自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便地扩展。

2)当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。

3)根据用户自定义函数类别分为以下三种:

  • UDF(User-Defined-Function)
    • 一进一出。
  • UDAF(User-Defined Aggregation Function)
    • 用户自定义聚合函数,多进一出。
    • 类似于:count/max/min。
  • UDTF(User-Defined Table-Generating Functions)
    • 用户自定义表生成函数,一进多出。
    • 如 lateral view explode()。

4)官方文档地址

HivePlugins - Apache Hive - Apache Software Foundationicon-default.png?t=O83Ahttps://cwiki.apache.org/confluence/display/Hive/HivePlugins

5)编程步骤

  • (1)继承Hive提供的类
    • org.apache.hadoop.hive.ql.udf.generic.GenericUDF
    • org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
  • (2)实现类中的抽象方法
  • (3)在hive的命令行窗口创建函数
    • 添加jar。
      ADD JAR linux_jar_path;
    • 创建function。
      CREATE [TEMPORARY] FUNCTION [dbname.]function_name AS class_name;
  • (4)在hive的命令行窗口删除函数
    DROP [TEMPORARY] FUNCTION [IF EXISTS] [dbname.]function_name;

自定义UDF函数

0)需求

自定义一个UDF实现计算给定基本数据类型的长度,例如:

hive(default)> SELECT my_len("abcd");

输出结果应为4。

1)创建一个Maven工程Hive

2)导入依赖

<dependencies><dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>3.1.3</version></dependency>
</dependencies>

3)创建一个类

package com.lzl.hive.udf;import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;/*** 我们需计算一个给定基本数据类型的长度*/
public class MyUDF extends GenericUDF {/*** 判断传进来的参数的类型和长度* 约定返回的数据类型*/@Overridepublic ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {if (arguments.length != 1) {throw new UDFArgumentLengthException("Please give me only one arg.");}if (!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)) {throw new UDFArgumentTypeException(1, "I need primitive type arg.");}return PrimitiveObjectInspectorFactory.javaIntObjectInspector;}/*** 解决具体逻辑的*/@Overridepublic Object evaluate(DeferredObject[] arguments) throws HiveException {Object o = arguments[0].get();if (o == null) {return 0;}return o.toString().length();}@Override// 用于获取解释的字符串public String getDisplayString(String[] children) {return "";}
}

4)创建临时函数

  • (1)打成jar包上传到服务器 /opt/module/hive/datas/myudf.jar
  • (2)将jar包添加到hive的classpath,临时生效
    hive (default)> ADD JAR /opt/module/hive/datas/myudf.jar;
  • (3)创建临时函数与开发好的java class关联
    hive (default)> 
    CREATE TEMPORARY FUNCTION my_len 
    AS "com.lzl.hive.udf.MyUDF";
  • (4)即可在HQL中使用自定义的临时函数
    hive (default)> 
    SELECT ename,my_len(ename) ename_len 
    FROM emp;
    • (5)删除临时函数
      hive (default)> DROP TEMPORARY FUNCTION my_len;
      注意:临时函数只跟会话有关系,跟库没有关系。只要创建临时函数的会话不断,在当前会话下,任意一个库都可以使用,其他会话全都不能使用。

5)创建永久函数

  • (1)创建永久函数 注意:因为ADD JAR本身也是临时生效,所以在创建永久函数的时候,需要指定路径(并且因为元数据的原因,这个路径还得是HDFS上的路径)。
    hive (default)> 
    CREATE FUNCTION my_len2 
    AS "com.lzl.hive.udf.MyUDF" 
    USING JAR "hdfs://hadoop12:8020/udf/myudf.jar";
  • (2)即可在HQL中使用自定义的永久函数
    hive (default)> 
    SELECT ename,my_len2(ename) ename_len 
    FROM emp;
  • (3)删除永久函数
    hive (default)> DROP FUNCTION my_len2;
    注意:永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。 永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。 永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上 库名.函数名

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com