zoukankan      html  css  js  c++  java
  • hive高阶操作 窗口函数

    hive 窗口函数按照我个人理解,依据hive在map_reduce运算中,通过数据聚合,做好数据清洗和运算,一般在olap(在线数据分析)中事半功倍。

    假设以下工作场景:窗口函数的威力你就会见识到:

    1、比赛场景中,每场比赛的成绩排名第二位的选手,或者每场比赛成绩排名前五的选手;

    2、如果有选手淘汰,每一个选手上次参赛的时间,或者最后第二次参赛的时间;

    3、每场比赛,前20%的选手

    场景陆续添加中

    窗口函数分类

    1、SUM,AVG,MIN,MAX
    2、NTILE,ROW_NUMBER,RANK,DENSE_RANK
    3、CUME_DIST,PERCENT_RANK
    4、LAG,LEAD,FIRST_VALUE,LAST_VALUE
    5、GROUPING SETS,GROUPING__ID,CUBE,ROLLUP

      • RANK() :在分组中排名,相同排名时会留下空位;
      • DENSE_RANK() :在分组中排名,相同排名时不会留下空位;
      • FIRST_VALUE() :分组内排序取第一个值;
      • LAST_VALUE() :分组内排序取最后一个值;
      • NTILE(n) :将分组数据按顺序切分成n份,返回当前所在切片;
      • ROW_NUMGBER() :在分组中从1开始按序记录序列;
      • CUME_DIST() :小于等于当前值的行数 / 分组总行数(百分比);
      • PERCENT_RANK() :(分组内的RANK值-1) / (分组内总数-1);
      • LAG(col, n, DEFAULT) :在统计窗口内从下往上取第n行的值;
      • LEAD(col, n, DEFAULT):在统计窗口内从上往下取第n行的值;

    第一步:先理解 partition by字句。

             hive 属于分区查询,当然还是在map_reduce运算上做文章。Partition By子句也可以称为查询分区子句,非常类似于Group By,都是将数据按照边界值分组,而Over之前的函数在每一个分组之内进行,如果超出了分组,则函数会重新计算。

    大牛案例:按照月份聚合,并非按照name,sum按照每月的总cost求和

    select name,orderdate,cost,sum(cost) over(partition by month(orderdate))
    from t_window
    name    orderdate   cost    sum_window_0
    jack    2015-01-01  10  205
    jack    2015-01-08  55  205
    tony    2015-01-07  50  205
    jack    2015-01-05  46  205
    tony    2015-01-04  29  205
    tony    2015-01-02  15  205
    jack    2015-02-03  23  23
    mart    2015-04-13  94  341
    jack    2015-04-06  42  341
    mart    2015-04-11  75  341
    mart    2015-04-09  68  341
    mart    2015-04-08  62  341
    neil    2015-05-10  12  12

    第二步:理解查询语句内部顺序:

    - 如果只使用partition by子句,未指定order by的话,我们的聚合是分组内的聚合. 
    - 使用了order by子句,未使用window子句的情况下,默认从起点到当前行

    window子句: 
    n PRECEDING:往前n行数据
    n FOLLOWING:往后n行数据 
    - CURRENT ROW:当前行 
    - UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING:表示到后面的终点

    大牛案例:

    select name,orderdate,cost,
    sum(cost) over() as sample1,--所有行相加
    sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加
    sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加
    sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row )  as sample4 ,--和sample3一样,由起点到当前行的聚合
    sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING   and current row) as sample5, --当前行和前面一行做聚合
    sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING   AND 1 FOLLOWING  ) as sample6,--当前行和前边一行及后面一行
    sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行
    from t_window

    查询结果

    name orderdate cost sample1 sample2 sample3 sample4 sample5 sample6 sample7
    jack    2015-01-01  10  661 176 10  10  10  56  176
    jack    2015-01-05  46  661 176 56  56  56  111 166
    jack    2015-01-08  55  661 176 111 111 101 124 120
    jack    2015-02-03  23  661 176 134 134 78  120 65
    jack    2015-04-06  42  661 176 176 176 65  65  42
    mart    2015-04-08  62  661 299 62  62  62  130 299
    mart    2015-04-09  68  661 299 130 130 130 205 237
    mart    2015-04-11  75  661 299 205 205 143 237 169
    mart    2015-04-13  94  661 299 299 299 169 169 94
    neil    2015-05-10  12  661 92  12  12  12  92  92
    neil    2015-06-12  80  661 92  92  92  92  92  80
    tony    2015-01-02  15  661 94  15  15  15  44  94
    tony    2015-01-04  29  661 94  44  44  44  94  79

    第三步:八仙过海,各显神通。

    下面是各个窗口函数的骚操作,车速较高,扶好站稳。

    1、排名前几位的选手——类似问题,前20%的选手

    NTILE,ROW_NUMBER,RANK,DENSE_RANK

    - row_number()从1开始,按照顺序,生成分组内记录的序列,row_number()的值不会存在重复,当排序的值相同时,按照表中记录的顺序进行排列 
    --rank() 跳跃排序,如果有两个第一级别时,接下来是第三级别
    --dense_rank() 连续排序,如果有两个第一级别时,接下来是第二级别

    **注意: 
    rank和dense_rank的区别在于排名相等时会不会留下空位

    SELECT 
    cookieid,
    createtime,
    pv,
    RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn1,
    DENSE_RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn2,
    ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn3 
    FROM lxw1234 
    WHERE cookieid = 'cookie1';
    查询结果:
    cookieid day           pv       rn1     rn2     rn3 
    cookie1 2015-04-12      7       1       1       1
    cookie1 2015-04-11      5       2       2       2
    cookie1 2015-04-15      4       3       3       3
    cookie1 2015-04-16      4       3       3       4
    cookie1 2015-04-13      3       5       4       5
    cookie1 2015-04-14      2       6       5       6

    查询前20%的记录

    NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。

    注意:n必须为int类型。

    select * from (
        select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
        from business) t
    where sorted = 1;

    2、上一次记录

    LAG,LEAD,FIRST_VALUE,LAST_VALUE

    LAG(col,n):往前第n行数据
    LEAD(col,n):往后第n行数据

    select name,orderdate,cost,
    lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1,
    lag(orderdate,2) over (partition by name order by orderdate) as time2
    from t_window
    
    
    查询结果:
    name    orderdate   cost    time1   time2
    jack    2015-01-01  10  1900-01-01  NULL
    jack    2015-01-05  46  2015-01-01  NULL
    jack    2015-01-08  55  2015-01-05  2015-01-01
    jack    2015-02-03  23  2015-01-08  2015-01-05
    jack    2015-04-06  42  2015-02-03  2015-01-08
    mart    2015-04-08  62  1900-01-01  NULL
    mart    2015-04-09  68  2015-04-08  NULL
    mart    2015-04-11  75  2015-04-09  2015-04-08
    mart    2015-04-13  94  2015-04-11  2015-04-09

    first_value取分组内排序后,截止到当前行,第一个值 
    last_value取分组内排序后,截止到当前行,最后一个值

    select name,orderdate,cost,
    first_value(orderdate) over(partition by name order by orderdate) as time1,
    last_value(orderdate) over(partition by name order by orderdate) as time2
    from t_window
    
    查询结果
    name    orderdate   cost    time1   time2
    jack    2015-01-01  10  2015-01-01  2015-01-01
    jack    2015-01-05  46  2015-01-01  2015-01-05
    jack    2015-01-08  55  2015-01-01  2015-01-08
    jack    2015-02-03  23  2015-01-01  2015-02-03
    jack    2015-04-06  42  2015-01-01  2015-04-06
    mart    2015-04-08  62  2015-04-08  2015-04-08
    mart    2015-04-09  68  2015-04-08  2015-04-09
    mart    2015-04-11  75  2015-04-08  2015-04-11
    mart    2015-04-13  94  2015-04-08  2015-04-13
    neil    2015-05-10  12  2015-05-10  2015-05-10
    neil    2015-06-12  80  2015-05-10  2015-06-12

    本文参考案例:

    hive :窗口函数案例

    hive分析函数解释

    天才是百分之一的灵感,加百分之九十九的汗水,但那百分之一的灵感往往比百分之九十九的汗水来的重要
  • 相关阅读:
    EzHttp 流传输调用代码示例
    使用EzHttp框架 开发基于HTTP协议的CS轻应用
    [转]Installing Memcached on Windows
    SQLiteServer+SQLiteClient 用于.Net项目的SQLite服务端程序和客户端类库
    ERROR: Pillow-5.2.0-cp35-cp35m-win_amd64.whl is not a supported wheel on this platform.
    Linux下的tar压缩解压缩命令详解
    scp 基于 SSH 的安全远程服务器文件拷贝
    大批量删除列表中元素的方法,自己用本办法做的
    Python 列表 pop() 方法
    可遍历的数据对象enumerate() 方法的使用
  • 原文地址:https://www.cnblogs.com/Christbao/p/12095320.html
Copyright © 2011-2022 走看看