Hive 学习总结

    这一周主要学习了 Hive 的一些基础知识,学习了多个 Hive 窗口函数,虽然感觉这些窗口函数没有实际的应用意义,但还是都了解了一下。

sum()over()

:可以实现在窗口中实现逐行累加

其他 avg、count、min、max 的用法一样

#要先有一个统计出每个月总额的表,这里就是 t_access_amount 表,如下图一

# partition by uid:根据uid 分组,order by month :根据月份排序,

rows between unbounded preceding and current_row:选择 无边界的前面的行和当前行之间的行,最后是求 sum 即和。得到下图二

# 是在窗口求和,而窗口的定义时按照 uid 分区 order by 排序得到的。得到一个字段

select uid,month,amount,

sum(amount)over(partition by uid order by month rows between unbounded preceding and  current_row ) as accumulate from t_access_amount;

preceding:前面的,后来的,往序号变大的方向

following:往后

2 preceding :表示前2行

3 following :表示后3行

unbounded preceding:表示从第1行开始,从前面的起点

unbounded following:表示最后一行,从后面的终点

注意:使用 rows between 时,按order by 顺序编号(没有指定order by 会默认排序)需要左边是小编号右边是大编号

rows between unbounded following and current row  是错的,应该写作

rows between current row and unbounded following 是当前行到终点行

rows between current row and 1 preceding   也是错的,应该写作

rows between 1 preceding andcurrent row 表示前1行和当前行

select

   cookieid,

   createtime,

   pv,

   # 得到显示的排序编号

   row_number() over(partition by cookieid order by createtime) as rn,

   # 从前面的起点到当前位置,这里是从分区最后一行到当前行的和

   sum(pv) over (partition by cookieid order by createtime rows between unbounded preceding and current row) as pv1,

   # 和上面一样(加 order by 和不加效果不一样)

   sum(pv) over (partition by cookieid order by createtime) as pv2,

#省略了 rows betweent 窗口函数,表示分区的所有数据

   sum(pv) over (partition by cookieid) as pv3,

   # 前面3行+当前后

   sum(pv) over (partition by cookieid order by createtime rows between 3 preceding and current row) as pv4,

# 前面3行+当前行+后面1行

   sum(pv) over (partition by cookieid order by createtime rows between 3 preceding and 1 following) as pv5,

   # 当前行+后面所有行

   sum(pv) over (partition by cookieid order by createtime rows between current row and unbounded following) as pv6

from cookie1;


注意:上面显示的排序结果不太对,所以看起来好像结果是相反的一样,实际上单独拿出来运行是对的,可以看以相同方式排序的 rn 编号。

2、row_numver()over()函数、NTILE、RANK、DENSE_RANK

注意:这上面这些都不支持使用 rows between 语句,row_number() 展示出来的排序会和查询字段的最后一个 over(order by)里面的顺序一样

:分组 TOPN,即可以分组后排序,便于找到最好的几条数据

eg:有如下数据,要查出每种性别中年龄最大的2条数据

1,18,a,male

2,19,b,male

3,22,c,female

4,16,d,female

5,30,e,male

6,26,f,female

分析:如果使用按性别分组,是可以分出两条数据,但是分组的缺点是只能查出聚合函数(聚合函数只能产生一组中的一个值)和分组依据。而这里是要求多条数据(2个)

# 正确操作,这里先 partition by sex字段分组,然后根据每一组的 age 字段降序排序。得到的序号 1,2,3 等取名为 rn ,然后通过 where 判断 前两个就是结果

# rn 字段是一个分组标记 序号,如下图是中间(select ...)括号的结果

select * from

(select id,age,sex,row_number( ) over(partition by sex order by age desc)as rn from t_user)tmp

where rn<3;

NTILE(n) 

:用于将分组数据按照顺序切分成 n 片(不一定是平均),然后每一份都编号为1-n,这样就可以拿到想要那一份数据。如果切片不均匀,默认增加第一个切片的分布,例如,14 条记录切3片就切不好,就会切成 6、4、4,其中6那份编号为1。

注意:可以不指定 order by

select

  cookieid,

  createtime,

  pv,

  ntile(2) over (partition by cookieid order by createtime) as rn2, --分组内将数据分成2片

  ntile(3) over (partition by cookieid order by createtime) as rn3, --分组内将数据分成3片

  ntile(4) over (order by createtime) as rn4 --将所有数据分成4片

from cookie2

order by cookieid,createtime;


应用:

    统计各个 cookieid,pv 数最多的前1/3天的数据

select * from(

select *,ntile(3) over(partition by cookieid order by pv desc) as sn3 from cookie2) a where a.sn3=1;

RANK()

:生成数据项再分组中的排名,排名相等会在名次中留下空位

dense_rank()

:生成数据项再分组中的排名,排名相等不会再名次中留下空位

注意:上面两者都需要指定 order by,不然排名都是1

select

  cookieid,

  createtime,

  pv,

  rank() over (partition by cookieid order by pv desc) as r1,

  dense_rank() over (partition by cookieid order by pv desc) as r2,

  row_number() over (partition by cookieid order by pv desc) as rn

from cookie.cookie2

where cookieid='cookie1';

根据上图,可知区别:

    rank():按顺序编号,相同分组排序有相同的排名,但是会占位,后面的排名隔一位,就是成绩一样名次相同,但是后面的名次得低两位。

    dense_rank():按顺序编号,相同分组排序有相同的排名,后面排名顺序不边就是有并列第几名的情况。

    row_number() :按顺序编号,不会有相同的编号,即使分组排序是相同的。

cume_dist

:小于等于当前值的行数/分组内总行数,注意这个要指定排序方式,不然全都是1

select 

  *,

  # 对 pv 降序排序后,计算小于等于当前行 pv 值得行数占总行数得比分

  cume_dist() over(order by pv) as rn1,

  # 计算cookieid 分组内,小于等于当前行 pv 值的行数占总行数的比分

  cume_dist() over(partition by cookieid order by pv) as rn2 

from cookie3;

percent_rank

:分组内当前行的(rank 值-1)/(分组内总行数-1)

select 

  * ,

  # 求得 rank 值

  rank() over(order by pv) as r1,

  # 求得总共有多少行,这里用 sum(1) 效果一样

  count(1) over() as c1 ,

  # 得到的结果其实就是 rank -1/count(1) -1

  percent_rank() over(order by pv) as p1  

from cookie3;

总结:排序、切片、编号、的都需要使用 order by,不然会全都是1,但是除了 row_number() 因为这个函数编号不重复且顺延,所以还是会有编号,但是不确定编号逻辑。

lag

:用于获得窗口内往上第n行的值,n>=0

第一个参数为列名

第二个参数为往上第n行(可选,默认为1)

第三个参数为默认值(当往上第n行为NULL时,取默认值,如不指定,则为NULL)

# 就是用往上多少行的数据来替换当前行,可以为0,但是不能为负数

select

   *,

   row_number() over(partition by cookieid order by createtime) as r1,

   lag(createtime,1) over(partition by cookieid order by createtime) as la1,

   lag(createtime,2,'this is tidai') over(partition by cookieid order by createtime) as la2 from cookie4;

lead

:与lag 相反,用于获取窗口内往下第n 行的值,n>=0

第一个参数为列名

第二个参数为往上第n行(可选,默认为1)

第三个参数为默认值(当往上第n行为NULL时,取默认值,如不指定,则为NULL)

select

   *,

   row_number() over(partition by cookieid order by createtime) as r1,

   lead(createtime,1) over(partition by cookieid order by createtime) as la1,

   lead(createtime,2,'this is tidai') over(partition by cookieid order by createtime) as la2 from cookie4;

last_value

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

first_value

:取分组内排序后,第一个值

select 

  *,

  # 展示排序好像和最后一个 over 里面的 order by 有关

  row_number() over(partition by cookieid order by createtime) as r1,

  # 获取最后一个值,但是其实都还是自己,因为只到当前行 

  last_value(url) over(partition by cookieid order by createtime) as l1,

# 转换一下 order by 为desc,这样第一个就是之前的最后一个,可以避免 rn 为1的写法,但是如果有多个字段去重那还是取 rn=1 的方便些

  first_value(url) over(partition by cookieid order by createtime desc ) as f1 from cookie4;

注意:使用窗口分析函数时,要特别注意 order by 的使用,如果使用的不恰当会导致统计的不是我们想要的。row_number() over() 的展示排序好像时根据最后一个字段的over(order by)来展示的

grouping sets 、grouping__id、cube、rollup

这几个分析函数通常用于 olap 中,不能累加,而且需要根据不同维度上钻和下钻的指标统计,比如分 时、分、天、月的 UV 数

grouping__id

:表示结果属于哪一个分组集合,注意中间是两个下划线

select 

  month ,

  day,

  count(distinct cookieid) as uv,

  GROUPING__ID 

from cookie5 group by month ,day 

grouping sets(month,day) 

order by GROUPING__ID;

第一列时按照 month 进行分组的,

第二列时按照 day 进行分组的

第三列时按照 对应month、day 分组统计出来的结果

第四列 grouping__id 表示这一组结果属于哪个分组集合

注意:grouping sets 里面就是说明以什么分组,上面的group by 是指定可以进行组合的分组字段sets 里面的只能使用这里指定的字段,

如,这里 grouping sets(month , day) 表示分别根据 month、day 字段分组,               grouping sets(month,day,(month,day)) 则表示分别根据 month、day、month和day 分组。  

这里group by 和 grouping sets 可以搭配使用,不是这里的专属,并且这里也可以不用 groupind sets

select

  month ,

  day,

  count(distinct cookieid) as uv,

  GROUPING__ID

from cookie5 group by month ,day

grouping sets(month,day,(month,day))

order by GROUPING__ID;

# 上面的语句执行结果等价于下面的

SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__IDFROM cookie5GROUP BY month

UNION ALL

SELECTNULL,day,COUNT(DISTINCT cookieid) AS uv,2 ASGROUPING__ID FROM cookie5GROUP BY day

UNION ALL

SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 ASGROUPING__ID FROM cookie5GROUP BY month,day

cube

:根据group by 的维度的所有组合进行聚合,就是省略 grouping sets ,直接将group by 后面的字段以各种可能的形式分组,然后union all 得到结果。

select 

  month,

  day,

  count(distinct cookieid) as uv,

  grouping__id 

from cookie5 

group by month,day with cube

order by grouping__id;

等价于下面的语句

SELECTNULL,NULL,COUNT(DISTINCT cookieid) AS uv,0 AS GROUPING__ID FROM cookie5 -- 不分组

UNION ALL

SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM cookie5GROUP BY month  --只对 month 分组

UNION ALL

SELECTNULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM cookie5GROUP BY day  --只对 day 分组

UNION ALL

SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM cookie5GROUP BY month,day  -- 对 month、day 分组

rollup

:是 cube 的子集,以最左侧的维度为主,从该维度进行层级聚合

# 是cube 的子集,以 month 为主,保留 month、month+day、不指定分组 三种情况

select 

  month,

  day,

  count(distinct cookieid) as uv ,

  grouping__id 

from cookie5 

group by month,day with rollup 

order by grouping__id;

上面可以实现一个叫上钻的效果:

    月天的uv==》月的uv==》总的uv

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容