掌握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, --订单id
  user_id    STRING, -- 用户id
  user_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)需求实现
SELECT
  order_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)需求实现
SELECT
  order_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)需求实现
SELECT
  order_id,
  user_id,
  user_name,
  order_date,
  order_amount,
  NVL(DATEDIFF(order_date, last_order_date), 0) diff
FROM
(
  SELECT
    order_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_date
  FROM 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)需求实现
SELECT
  order_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)需求实现
SELECT
  order_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 {
  /**
   * 判断传进来的参数的类型和长度
   * 约定返回的数据类型
   */
  @Override
  public 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;
  }

  /**
   * 解决具体逻辑的
   */
  @Override
  public 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;
    注意:永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。 永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。 永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上 库名.函数名

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据深度洞察

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值