相信用過MySQL的朋友都知道,MySQL中也有開窗函數的存在。開窗函數的引入是爲了既顯示彙集前的數據,又顯示彙集後的數據。即在每一行的最後一列添加聚合函數的結果。javascript
開窗用於爲行定義一個窗口(這裏的窗口是指運算將要操做的行的集合),它對一組值進行操做,不須要使用 GROUP BY 子句對數據進行分組,可以在同一行中同時返回基礎行的列和聚合列。java
聚合函數是將多行變成一行,count,avg…node
開窗函數是將一行變成多行;sql
聚合函數若是要顯示其餘的列必須將列加入到group by中shell
開窗函數能夠不使用group by,直接將全部信息顯示出來數組
聚合函數(列) OVER(選項),這裏的選項能夠是PARTITION BY 子句,但不能夠是 ORDER BY 子句。markdown
排序函數(列) OVER(選項),這裏的選項能夠是ORDER BY 子句,也能夠是OVER(PARTITION BY 子句 ORDER BY 子句),但不能夠是 PARTITION BY 子句。ide
進入到SparkShell命令行函數
/export/servers/spark/bin/spark-shell --master spark://node01:7077,node02:7077
建立一個樣例類,用於封裝數據大數據
case class Score(name: String, clazz: Int, score: Int)
建立一個RDD數組,造一些數據,並調用toDF
方法將其轉換成DataFrame
val scoreDF = spark.sparkContext.makeRDD(Array( Score("a1", 1, 80), Score("a2", 1, 78), Score("a3", 1, 95), Score("a4", 2, 74), Score("a5", 2, 92), Score("a6", 3, 99), Score("a7", 3, 99), Score("a8", 3, 45), Score("a9", 3, 55), Score("a10", 3, 78), Score("a11", 3, 100)) ).toDF("name", "class", "score")
建立一個臨時表
scoreDF.createOrReplaceTempView("scores")
查詢全部數據
scoreDF.show() +----+-----+-----+ |name|class|score| +----+-----+-----+ | a1| 1| 80| | a2| 1| 78| | a3| 1| 95| | a4| 2| 74| | a5| 2| 92| | a6| 3| 99| | a7| 3| 99| | a8| 3| 45| | a9| 3| 55| | a10| 3| 78| | a11| 3| 100| +----+-----+-----+
OVER 關鍵字表示把聚合函數當成聚合開窗函數而不是聚合函數。
SQL標準容許將全部聚合函數用作聚合開窗函數。
spark.sql("select count(name) from scores").show
spark.sql("select name, class, score, count(name) over() name_count from scores").show
查詢結果以下所示:
查詢結果以下所示: +----+-----+-----+----------+ |name|class|score|name_count| +----+-----+-----+----------+ | a1| 1| 80| 11| | a2| 1| 78| 11| | a3| 1| 95| 11| | a4| 2| 74| 11| | a5| 2| 92| 11| | a6| 3| 99| 11| | a7| 3| 99| 11| | a8| 3| 45| 11| | a9| 3| 55| 11| | a10| 3| 78| 11| | a11| 3| 100| 11| +----+-----+-----+----------+
開窗函數的 OVER 關鍵字後括號中的可使用 PARTITION BY 子句來定義行的分區來供進行聚合計算。與 GROUP BY 子句不一樣,PARTITION BY 子句建立的分區是獨立於結果集的,建立的分區只是供進行聚合計算的,並且不一樣的開窗函數所建立的分區也不互相影響。
下面的 SQL 語句用於顯示按照班級分組後每組的人數:
OVER(PARTITION BY class)表示對結果集按照 class 進行分區,而且計算當前行所屬的組的聚合計算結果。
spark.sql("select name, class, score, count(name) over(partition by class) name_count from scores").show
查詢結果以下所示:
+----+-----+-----+----------+ |name|class|score|name_count| +----+-----+-----+----------+ | a1| 1| 80| 3| | a2| 1| 78| 3| | a3| 1| 95| 3| | a6| 3| 99| 6| | a7| 3| 99| 6| | a8| 3| 45| 6| | a9| 3| 55| 6| | a10| 3| 78| 6| | a11| 3| 100| 6| | a4| 2| 74| 2| | a5| 2| 92| 2| +----+-----+-----+----------+
row_number() over(order by score) as rownum 表示按score 升序的方式來排序,並得出排序結果的序號
注意:
在排序開窗函數中使用 PARTITION BY 子句須要放置在ORDER BY 子句以前。
spark.sql("select name, class, score, row_number() over(order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a8| 3| 45| 1| | a9| 3| 55| 2| | a4| 2| 74| 3| | a2| 1| 78| 4| | a10| 3| 78| 5| | a1| 1| 80| 6| | a5| 2| 92| 7| | a3| 1| 95| 8| | a6| 3| 99| 9| | a7| 3| 99| 10| | a11| 3| 100| 11| +----+-----+-----+----+
spark.sql("select name, class, score, row_number() over(partition by class order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a2| 1| 78| 1| | a1| 1| 80| 2| | a3| 1| 95| 3| | a8| 3| 45| 1| | a9| 3| 55| 2| | a10| 3| 78| 3| | a6| 3| 99| 4| | a7| 3| 99| 5| | a11| 3| 100| 6| | a4| 2| 74| 1| | a5| 2| 92| 2| +----+-----+-----+----+
rank() over(order by score) as rank表示按 score升序的方式來排序,並得出排序結果的排名號。
這個函數求出來的排名結果能夠並列(並列第一/並列第二),並列排名以後的排名將是並列的排名加上並列數
簡單說每一個人只有一種排名,而後出現兩個並列第一名的狀況,這時候排在兩個第一名後面的人將是第三名,也就是沒有了第二名,可是有兩個第一名。
spark.sql("select name, class, score, rank() over(order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a8| 3| 45| 1| | a9| 3| 55| 2| | a4| 2| 74| 3| | a10| 3| 78| 4| | a2| 1| 78| 4| | a1| 1| 80| 6| | a5| 2| 92| 7| | a3| 1| 95| 8| | a6| 3| 99| 9| | a7| 3| 99| 9| | a11| 3| 100| 11| +----+-----+-----+----+
spark.sql("select name, class, score, rank() over(partition by class order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a2| 1| 78| 1| | a1| 1| 80| 2| | a3| 1| 95| 3| | a8| 3| 45| 1| | a9| 3| 55| 2| | a10| 3| 78| 3| | a6| 3| 99| 4| | a7| 3| 99| 4| | a11| 3| 100| 6| | a4| 2| 74| 1| | a5| 2| 92| 2| +----+-----+-----+----+
dense_rank() over(order by score) as dense_rank 表示按score 升序的方式來排序,並得出排序結果的排名號。
這個函數並列排名以後的排名是並列排名加1
簡單說每一個人只有一種排名,而後出現兩個並列第一名的狀況,這時候排在兩個第一名後面的人將是第二名,也就是兩個第一名,一個第二名
spark.sql("select name, class, score, dense_rank() over(order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a8| 3| 45| 1| | a9| 3| 55| 2| | a4| 2| 74| 3| | a2| 1| 78| 4| | a10| 3| 78| 4| | a1| 1| 80| 5| | a5| 2| 92| 6| | a3| 1| 95| 7| | a6| 3| 99| 8| | a7| 3| 99| 8| | a11| 3| 100| 9| +----+-----+-----+----+
spark.sql("select name, class, score, dense_rank() over(partition by class order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a2| 1| 78| 1| | a1| 1| 80| 2| | a3| 1| 95| 3| | a8| 3| 45| 1| | a9| 3| 55| 2| | a10| 3| 78| 3| | a6| 3| 99| 4| | a7| 3| 99| 4| | a11| 3| 100| 5| | a4| 2| 74| 1| | a5| 2| 92| 2| +----+-----+-----+----+
ntile(6) over(order by score)as ntile表示按 score 升序的方式來排序,而後 6 等分紅 6 個組,並顯示所在組的序號。
spark.sql("select name, class, score, ntile(6) over(order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a8| 3| 45| 1| | a9| 3| 55| 1| | a4| 2| 74| 2| | a2| 1| 78| 2| | a10| 3| 78| 3| | a1| 1| 80| 3| | a5| 2| 92| 4| | a3| 1| 95| 4| | a6| 3| 99| 5| | a7| 3| 99| 5| | a11| 3| 100| 6| +----+-----+-----+----+
spark.sql("select name, class, score, ntile(6) over(partition by class order by score) rank from scores").show() +----+-----+-----+----+ |name|class|score|rank| +----+-----+-----+----+ | a2| 1| 78| 1| | a1| 1| 80| 2| | a3| 1| 95| 3| | a8| 3| 45| 1| | a9| 3| 55| 2| | a10| 3| 78| 3| | a6| 3| 99| 4| | a7| 3| 99| 5| | a11| 3| 100| 6| | a4| 2| 74| 1| | a5| 2| 92| 2| +----+-----+-----+----+
本次的分享就到這裏,受益的朋友或對大數據技術感興趣的夥伴能夠點個贊關注一下博主,後續會持續更新大數據的相關內容,敬請期待(✪ω✪)