本篇主要來介紹一下hive中三個常用的排序函數(shù)row_number(),rank()和dense_rank()。
1悄但、數(shù)據(jù)
先來看一下我們的數(shù)據(jù)。我們使用spark往hive數(shù)據(jù)庫中寫入數(shù)據(jù):
import spark.implicits._
val seqData = Seq(
("1班","小A","70"),
("2班","小B","84"),
("3班","小C","70"),
("1班","小D","89"),
("1班","小E","70"),
("2班","小F","90"),
("3班","小G","85"),
("3班","小H","68"),
("2班","小I","96"),
("1班","小J",null)
)
val seq2df = seqData
.toDF("class","student","score")
seq2df.write.saveAsTable("default.classinfo3")
數(shù)據(jù)結(jié)構(gòu)如下:
為了方便后續(xù)的介紹缕探,我們將幾名同學的成績設(shè)置為同樣的分數(shù)翎蹈。在介紹具體的函數(shù)前,咱們先簡單介紹下over遍愿。
row_number(),rank()和dense_rank()都是結(jié)合over來進行使用的存淫,over的一般結(jié)構(gòu)如下:
over(partition by col1 order by col2 asc/desc)
一般來說,需要指定以下三項:
1沼填、partition by col1桅咆,按哪列進行分組,如果不指定坞笙,則默認按全局進行排序岩饼,如果指定了一列荚虚,則首先對數(shù)據(jù)按照指定的列進行分組,然后進行組內(nèi)排序籍茧。
2版述、order by col2,指定按哪列進行排序硕糊,這個是必須要指定的院水,不指定會報錯。
3简十、asc/desc,按升序或降序進行排列撬腾,不指定的話螟蝙,默認是升序。
當然民傻,除了本文介紹的方法外胰默,over還可以結(jié)合其他許多函數(shù),如lag/lead/sum等漓踢,后續(xù)我們會繼續(xù)介紹牵署。
2、row_number()
使用row_number()進行排序喧半,即使排序列取值相同奴迅,仍然會賦予不同的排名,比如我們按照全局進行降序排序:
select
*,
row_number() over(order by score desc) as rank
from
default.classinfo3
輸出結(jié)果如下:
我們有以下結(jié)論:
1挺据、可以看到小A取具、小C、小E的分數(shù)都是70分扁耐,但排名分別是6暇检、7和8。
2婉称、我們故意在數(shù)據(jù)中插入了一個null值块仆,可以看到,按降序排的話null值的排名是最低的王暗。如果按升序排列悔据,那么null則會排名第一。
3瘫筐、row_number()的排序從1開始蜜暑,而我們上一篇介紹的posexplode是從0開始的。
然后再看下按班級排名的結(jié)果:
select
*,
row_number() over(partition by class order by score desc) as rank
from
default.classinfo3
結(jié)果如下:
這里留一個小疑惑策肝,對于排序列相同取值的結(jié)果肛捍,是怎么決定其對應的排名的呢隐绵?
3、rank()
再來看下rank拙毫,使用rank進行排序依许,如果排序列取值相同,那么其排名相同缀蹄,假設(shè)有3名同學排名第1峭跳,那么下一名同學的排名直接變?yōu)榈?。通過sql驗證下:
select
*,
rank() over(order by score desc) as rank
from
default.classinfo3
可以看到缺前,小A蛀醉、小C和小E的排名都是第6,可憐的小H直接排名第9了衅码。同時對于null值的排序跟row_number()相同拯刁。
4、dense_rank()
最后來看下dense_rank逝段,使用dense_rank進行排序垛玻,如果排序列取值相同,那么其排名相同奶躯,假設(shè)有3名同學排名第1帚桩,那么下一名同學的排名是2,而非4嘹黔。通過sql驗證下:
select
*,
dense_rank() over(order by score desc) as rank
from
default.classinfo3
結(jié)果如下:
可以看到账嚎,小A、小C和小E的排名都是第6参淹,小H排名是第7而非第9醉锄。同時對于null值的排序跟row_number()相同。