当前位置:   article > 正文

Hive常见的计算(连续纸,topN,行专列,列转行)_hive的数据计算使用

hive的数据计算使用

目录

1. 连续值

第1步:先按照条件开窗分组排序,得到分组排序的结果。排序字段值 减去 排序序列号

第2步:按照用户id 和 差值gid 分组。聚合得到一个总行数count,再按照连续值去过滤总行数count。

2. topN

第1步:开窗分组排序

第2步:求相邻排名间的分差,

3. 行转列

 翻转转换

step a. 按照用户分组

step b. 使用case when 新增字段,并赋值。

分组聚拢

step a. 按照用户分组

step b. 使用concat_ws等函数进行聚拢操作。

4. 列转行

5.  json字符串,字符串组的解析


1. 连续值

例如连续7天登录的用户,连续3天消费的用户等。

这主要是要有转换的思想。

将连续性转换为 ==》 差值相同

将连续值转换为 ==》 按照差值分组聚合的行数

step A- 需要开窗,在窗口内进行分组排序,上排序序列号gid

step B- 使用当前的排序字段值a 减去 排序序列号gid ( a - gid) ,得到新的一列。

step C- 再将连续值转换为判断差值大小,按照用户和差值分组。差值相同说明日期是连续的。根据求的连续值,去过滤步骤2得到的值,得到最终的结果集。

例如:求连续7天登录的用户。

数据: 第1列为用户ID, 第2列为登录日期,第3列为登录结果(1为成功,0为失败,即没有登录)

  1. -- user_id dt status(1 正常登录,0 异常)
  2. 1 2019-07-11 1
  3. 1 2019-07-12 1
  4. 1 2019-07-13 1
  5. 1 2019-07-14 1
  6. 1 2019-07-15 1
  7. 1 2019-07-16 1
  8. 1 2019-07-17 1
  9. 1 2019-07-18 1
  10. 2 2019-07-11 1
  11. 2 2019-07-12 1
  12. 2 2019-07-13 0
  13. 2 2019-07-14 1
  14. 2 2019-07-15 1
  15. 2 2019-07-16 0
  16. 2 2019-07-17 1
  17. 2 2019-07-18 0
  18. 3 2019-07-11 1
  19. 3 2019-07-12 1
  20. 3 2019-07-13 1
  21. 3 2019-07-14 0
  22. 3 2019-07-15 1
  23. 3 2019-07-16 1
  24. 3 2019-07-17 1
  25. 3 2019-07-18 1

按照步骤,

第1步:先按照条件开窗分组排序,得到分组排序的结果。排序字段值 减去 排序序列号

这里求得是用户,即按照用户分组,连续7天,按照登录日期排序。日期字段值 - 排序序列号。这个差值如果相同,说明日期连续

  1. -- 开窗排序, 开窗函数 over()
  2. over(partiton by user_id order by dt)
  3. -- 排名函数,给局部排序的上序列号,
  4. -- rank(),排名可以重复,相同排名的后续会有空位。即 1,2,3,3,5
  5. -- DENSE_RANK(), 排名可以重复,相同排名的后续不会有空位,1,2,3,3,4,5
  6. -- 这里排名 顺序增加 且 排名不会重复。使用 row_number()
  7. row_number() over(partiton by user_id order by dt)
  8. -- 求排序字段的当前值 和 排序序列号 的差值。 这里是日期的求值,直接使用date_sub
  9. date_sub(dt,row_number() over(partition by user_id order by dt))
  10. -- 最终第一步的sql是
  11. select user_id,
  12. dt,
  13. date_sub(dt,row_number() over(partition by user_id order by dt)) gid
  14. from user_login
  15. where status = 1

第2步:按照用户id 和 差值gid 分组。聚合得到一个总行数count,再按照连续值去过滤总行数count。

  1. -- 根据 当前字段值 和 排序序列号的差值,和用户分组。 最后过滤
  2. with tmp as (
  3. select user_id,
  4. dt,
  5. date_sub(dt,row_number() over(partition by user_id order by dt)) gid
  6. from user_login
  7. where status =1
  8. )
  9. select user_id,
  10. count(*) as login_count -- 连续登录的天数
  11. from tmp
  12. group by user_id,gid
  13. having login_count >= 7 -- having是在聚合函数count()后面执行,where则是之前执行。所以这里用

2. topN

求前几名排名。

这个排名不是全局,全局只要直接order by 字段就好了。指的是条件范围内的topN,即局部的topN,可能是局部的时间,局部的部门等。

比如求每个班级的前面三名,分数一样的并列,同时求出名次间的分差(即相邻排名的分差)

前面3名 ==》 排名函数( row_number【值相同时排名也不会相同】,rank【值相同时,排名也相同,且后续的排名值会断开】, dense_rank【值相同时,排名也相同,且后续的排名值不断开,会连续】)

相邻名词的分差 ==》 上下行的差值  ==》 将一列整体向上或者向下移动一行

  1. --student_id,class,score
  2. 1 1901 90
  3. 2 1901 90
  4. 3 1901 83
  5. 4 1901 60
  6. 5 1902 66
  7. 6 1902 23
  8. 7 1902 99
  9. 8 1902 67
  10. 9 1902 87

 期待的结果

  1. class score rnk lagscore
  2. 1901 90 1 0
  3. 1901 90 1 0
  4. 1901 83 2 -7
  5. 1901 60 3 -23
  6. 1902 99 1 0
  7. 1902 87 2 -12
  8. 1902 67 3 -20

实现思路:

step a. 求得是每个班级的,分数排名 ==》 按照班级分组,分数排序,再上排名函数。

step b. 两个相邻排名间的分差 ==》 M(score) 减去 M-1(score) ==》 需要分数,需要排名号

step c. 分数相同,并列排名, 后续的排名不会空 ==》 排名函数用 dense_rank()

sql实现:

第1步:开窗分组排序

  1. -- 第一步,得到分组排序的排名
  2. -- over() 开窗函数,按照班级分组,分数排序
  3. over(partition by class order by score desc)
  4. -- 前面3名,降序排名,排名重复不为空
  5. dense_rank() over(partition by class order by score desc)
  6. -- 分组排序的排名
  7. select student_id,
  8. class,
  9. score,
  10. dense_rank() over(partition by class order by score desc) as rnk -- 降序排名
  11. from student_table

第2步:求相邻排名间的分差,

相邻排名 ==》 相当于求连续值 ==》 对排名值字段进行开窗, 得到新的一列排名分数值

排名也是按照班级分组,分数排名 ==》 over(partition by class order by score desc)

相邻排名的分差 ==》 理解为把 一列的值整体移动,可以将减数那列上移一格,或者被减数那一列往下移动一格。 这里 采用 被减数下移一格

  1. -- 第一步得到的分班排名
  2. with tmp as (
  3. select sno,
  4. class,
  5. score,
  6. dense_rank() over (partition by class order by score desc) as rnk
  7. from student_table
  8. )
  9. -- 再次开窗,对班级分组,分数排名。 ==》 分组排名的分数
  10. over(partition by class order by score desc)
  11. -- 新增一行它的后续排名分数,他的值是 原来的排名分数列往下移动一行 ==》 lag() 函数往下移动一行
  12. lag(score) over(partition by class order by score desc)
  13. -- 求分差,空补0
  14. nvl(score - lag(score) over(partition by class order by score desc),0)
  15. -- 最终
  16. select class,
  17. score,
  18. nvl(score - lag(score) over (partition by class order by score desc), 0) lagscore
  19. from tmp
  20. where rank<=3; -- 前面3名

3. 行转列

 翻转转换

 原表名为 user_skill

  1. -- 数据:user_id skill
  2. 1 java
  3. 1 hadoop
  4. 1 hive
  5. 1 hbase
  6. 2 java
  7. 2 hive
  8. 2 spark
  9. 2 flink
  10. 3 java
  11. 3 hadoop
  12. 3 hive
  13. 3 kafka

求每个用户的组件技能情况,即期待输出

  1. id java hadoop hive hbase spark flink kafka
  2. 1 1 1 1 1 0 0 0
  3. 2 1 0 1 0 1 1 0
  4. 3 1 1 1 0 0 0 1

step a. 按照用户分组

step b. 使用case when 新增字段,并赋值。

  1. select id,
  2. sum(case when course="java" then 1 else 0 end) as java,
  3. sum(case when course="hadoop" then 1 else 0 end) as hadoop,
  4. sum(case when course="hive" then 1 else 0 end) as hive,
  5. sum(case when course="hbase" then 1 else 0 end) as hbase,
  6. sum(case when course="spark" then 1 else 0 end) as spark,
  7. sum(case when course="flink" then 1 else 0 end) as flink,
  8. sum(case when course="kafka" then 1 else 0 end) as kafka
  9. from user_skill
  10. group by user_id;

分组聚拢

相同的列数,将多个行值聚拢成一个行值

原表名为 row2line

  1. -- 数据。id1 id2 flag
  2. a b 2
  3. a b 1
  4. a b 3
  5. c d 6
  6. c d 8
  7. c d 8

期待输出

  1. -- 编写sql实现如下结果
  2. id1 id2 flag
  3. a b 2|1|3
  4. c d 6|8

思路: id1,id2的值没变 ==> 按照id1,id2分组

           flag的值是组合值  ==》 将原来分组好的flag值,聚拢起来,在拼接到一起

step a. 按照用户分组

step b. 使用concat_ws等函数进行聚拢操作。

  1. -- 分组聚拢
  2. -- 分组group by
  3. -- 聚拢可以使用 collect_set,collect_list。set会去重,这里的输出没有两个8,所以使用set
  4. select id1,
  5. id2,
  6. collect_set(flag) flag
  7. from row2line
  8. -- 将 集合中的值,拼接起来 ==》 concat_ws("拼接符", string or array)
  9. select id1,id2,
  10. concat_ws("|",collect_set(cast (flag as string))) flag
  11. from row2line

4. 列转行

将一行的值,拆分成多个行值  ==》  炸裂行数 explode() + lateral view

这个配合json的解析,会是实际工作中最常遇到的情况。

本例是上述的反转。即将

  1. -- 编写sql实现如下结果
  2. id1 id2 flag
  3. a b 2|1|3
  4. c d 6|8

转变为

  1. -- 数据。id1 id2 flag
  2. a b 2
  3. a b 1
  4. a b 3
  5. c d 6
  6. c d 8
  7. c d 8

explode(), udtf函数,它炸开字段时,不能与其他列在同一级

select id1,id2,explode(flag), 是不允许的。

lateral view: lateral view udtf[expression]  tableAlias as columnAlias

  1. -- 主要是关注explode的用法,搭配 udtf函数
  2. -- udtf函数 lateral view的用法
  3. select id1,id2,newflag
  4. from line2row
  5. lateral view explode(split(flag,"\\|")) t1 as newflag

5.  json字符串,字符串组的解析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/962682
推荐阅读
相关标签
  

闽ICP备14008679号