結構化資料上的 TopN 運算
【摘要】
TopN 查詢,即從資料中查詢前 N 名 / 後 N 名。TopN 查詢除了直接取值,還有查詢 TopN 所在記錄的詳細資訊,有時候還要查詢 TopN 所在的位置。另外 TopN 查詢還可能在分組中使用,用於查詢組內的前 N 名 / 後 N 名。這麼多種 TopN 查詢如何處理?這裡將為你全程剖析,並提供 esProc SPL 示例程式碼。
1. 最大值 / 最小值
最大值 / 最小值可以理解為 TopN 查詢中,N 等於 1 時的情況,因為很常用所以單獨拿出來講一下。取最大值 / 最小值是很常見的需求,例如一班數學最高分是多少,員工年齡最小的是幾歲等等。但是有時候我們並不關心具體的值,而是關心最大值 / 最小值出現的位置,這種需求常用於跨行計算。例如公司銷售額最高的那個月比上個月的銷售額增加了多少?此時我們需要知道銷售額最高月份所在記錄的行號,再取出上個月的銷售額與之比較。還有時候我們關心的是最大值 / 最小值所在記錄的詳細資訊。例如取一班數學最高分的同學姓名,公司年齡最小的員工在哪個部門等等。
本節將從以上三種情況來講解如何處理最大值 / 最小值的各種情況。以納斯達克指數為例,部分資料如下:
Date | Open | Close | Volume |
2019/01/02 | 6506.910156 | 6665.939941 | 2261800000 |
2019/01/03 | 6584.77002 | 6463.5 | 2607290000 |
2019/01/04 | 6567.140137 | 6738.859863 | 2579550000 |
2019/01/07 | 6757.529785 | 6823.470215 | 2507550000 |
2019/01/08 | 6893.439941 | 6897.0 | 2380290000 |
… | … | … | … |
1.1 取最大值 / 最小值
【例 1】 求納斯達克指數 2019 年最高收盤價。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019) | /選出 2019 年資料 |
3 | =A2.max(Close) | /使用函式 A.max() 獲取最高收盤價 |
同樣的例子,求納斯達克指數 2019 年最低收盤價:
|
A | B |
3 | =A2.min(Close) | /使用函式 A.min() 獲取最低收盤價 |
1.2 取最大值 / 最小值所在的行號
【例 2】 求 2019 年收盤價最高日,相比前一日的收盤價漲幅。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019).sort(Date) | /選出 2019 年資料並按日期排序 |
3 | =A2.pmax(Close) | /使用函式 A.pmax() 取出收盤價最高點所在的行號 |
4 | =A2.calc(A3,Close/Close[-1]-1) | /使用收盤價最大值與前日收盤價計算漲幅 |
最大值不一定是唯一的,如果想返回所有的行號,可以使用函式 A.pmax() 的 @a 選項:
|
A | B |
3 | =A2.pmax@a(Close) | /取出所有收盤價最高點記錄所在行號 |
如果希望從後向前定位,可以使用函式 A.pmax() 的 @z 選項:
|
A | B |
3 | =A2.pmax@z(Close) | /從後向前取出收盤價最高點記錄所在行號 |
1.3 取最大值 / 最小值所在的記錄
【例 3】 求納斯達克指數 2019 年最高點的日期。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019) | /選出 2019 年資料 |
3 | =A2.maxp(Close) | /使用函式 A.maxp() 取出收盤價最高點所在的記錄 |
4 | =A3.Date | /取出收盤價最高點的日期 |
同樣可以使用函式 A.minp() 來取最小值所在記錄:
|
A | B |
3 | =A2.minp(Close) | /使用函式 A.minp() 取出收盤價最低點所在的記錄 |
函式 A.maxp()和 A.minp() 同樣支援 @a 和 @z 選項,就不再逐一列舉了。
2. 前 N 個 / 後 N 個
取前 N 個 / 後 N 個的需求,與取最大值 / 最小值是類似的。我們同樣分為三類需求來詳細介紹。還是以納斯達克指數為例,部分資料如下:
Date | Open | Close | Volume |
2019/01/02 | 6506.910156 | 6665.939941 | 2261800000 |
2019/01/03 | 6584.77002 | 6463.5 | 2607290000 |
2019/01/04 | 6567.140137 | 6738.859863 | 2579550000 |
2019/01/07 | 6757.529785 | 6823.470215 | 2507550000 |
2019/01/08 | 6893.439941 | 6897.0 | 2380290000 |
… | … | … | … |
2.1 取前 N 個 / 後 N 個值
【例 4】 查詢納斯達克指數 2019 年成交量最高的 3 個量值。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019) | /選出 2019 年資料 |
3 | =A2.top(-3, Volume) | /使用函式 A.top(n,x) 獲取成交量最高的 3 個量值 |
同樣的例子,查詢納斯達克指數 2019 年成交量最低的 4 個量值:
|
A | B |
3 | =A2.top(4, Volume) | /使用函式 A.top(n,x) 獲取成交量最低的 4 個量值 |
2.2 取前 N 個 / 後 N 個所在的行號
【例 5】 查詢納斯達克指數 2019 年收盤價最高的 3 天中,交易量相對前一日的漲幅。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019).sort(Date) | /選出 2019 年資料並按日期排序 |
3 | =A2.ptop(-3, Close) | /使用函式 A.ptop(n,x) 取出最高的 3 個收盤價所在的行號 |
4 | =A3.run(~=A2(~).Volume/A2(~-1).Volume-1) | /迴圈使用當日交易量與前日交易量計算漲幅 |
2.3 取前 N 個 / 後 N 個所在的記錄
【例 6】 查詢納斯達克指數 2019 年成交量最低的 5 個交易日的交易資訊。
【SPL 指令碼】
|
A | B |
1 | =file("IXIC.txt").import@t() | /匯入納斯達克指數資料 |
2 | =A1.select(year(Date)==2019).sort(Date) | /選出 2019 年資料 |
3 | =A2.top(5; Close) | /使用函式 A.top(n; x) 取出成交量最低的 5 個交易日的記錄 |
3. 分組中的使用
除了分組彙總計算每組的最大值 / 最小值,查詢每組前 N 個 / 後 N 個也是很常見的需求。例如每個月賣的最好的 5 款商品是哪些,每年總銷售額前三名的客戶是哪些等等。本節我們會分類介紹,如何解決在分組中使用 TopN 的問題。
3.1 分組聚合中的最大值
【例 7】 查詢各班數學最高分。成績表部分資料如下:
CLASS | STUDENTID | SUBJECT | SCORE |
1 | 1 | English | 95 |
1 | 1 | Math | 90 |
1 | 1 | PE | 80 |
1 | 2 | English | 75 |
1 | 2 | Math | 84 |
… | … | … | … |
【SPL指令碼】
|
A | B |
1 | =file("Score.txt").import@t() | /匯入成績表資料 |
2 | =A1.select(Subject:"Math") | /選出數學成績 |
3 | =A2.groups(Class; max(Score):BestScore) | /按班級分組,使用 max() 函式統計各班數學最高分 |
3.2 分組後進行 TopN 運算
我們也可以把 TopN 查詢看作一種聚合運算。首先將資料按照一定的條件分組,然後再對每個分組後的結果集進行 TopN 查詢。我們分別按照取值和取記錄兩種情況來講解。
【例 8】 查詢各班數學前兩名的分數。成績表部分資料如下:
CLASS | STUDENTID | SUBJECT | SCORE |
1 | 1 | English | 95 |
1 | 1 | Math | 90 |
1 | 1 | PE | 80 |
1 | 2 | English | 75 |
1 | 2 | Math | 84 |
… | … | … | … |
【SPL指令碼】
|
A | B |
1 | =file("Score.txt").import@t() | /匯入成績表資料 |
2 | =A1.select(Subject:"Math") | /選出數學成績 |
3 | =A2.group(Class; ~.top(-2, Score):top2) | /按班級分組,使用函式 A.top() 統計各班數學前兩名的分數 |
4 | =A3.new(Class, top2(1):First, top2(2):Second) | /建立結果表,第一列是班級,第二列是第一名,第三列是第二名 |
【例 9】 查詢各班每科成績前三名的學生資訊。成績表部分資料如下:
CLASS | STUDENTID | SUBJECT | SCORE |
1 | 1 | English | 95 |
1 | 1 | Math | 90 |
1 | 1 | PE | 80 |
1 | 2 | English | 75 |
1 | 2 | Math | 84 |
… | … | … | … |
【SPL指令碼】
|
A | B |
1 | =file("Score.txt").import@t() | /匯入成績表資料 |
2 | =A1.group(Class,Subject;~.top(-3;Score):top3) | /按班級和學科分組並取出每組分數前兩名 |
3 | =A2.conj(top3) | /將所有班級各科前兩名對應的記錄合併 |
3.3 以累計方式進行 TopN 運算
以累計方式進行 TopN 運算,不會產生分組的結果集,常用於資料量比較大的時候。我們還是按照取值和取記錄兩種情況來講解。
【例 10】 求每個部門入職最早的兩個人的入職日期。僱員表的部分資料如下:
EID | NAME | DEPT | EntryDate |
1 | Rebecca | R&D | 2005/03/11 |
2 | Ashley | Finance | 2008/03/16 |
3 | Rachel | Sales | 2010/12/01 |
4 | Emily | HR | 2006/08/15 |
5 | Ryan | R&D | 2004/07/30 |
… | … | … | … |
【SPL 指令碼】
|
A | B |
1 | =file("Employee.txt").cursor@t() | /產生僱員表的遊標 |
2 | =A1.groups(Department; top(2,EntryDate):Top2) | /按部門分組並取出每組入職時間最早的兩個日期 |
3 | =A2.news(Top2;Department, ~:EntryDate) | /建立新表,第一列是部門,第二列是入職日期 |
【例 11】 求每個部門薪水前三高的員工資訊。僱員表的部分資料如下:
EID | NAME | DEPT | SALARY |
1 | Rebecca | R&D | 7000 |
2 | Ashley | Finance | 11000 |
3 | Rachel | Sales | 9000 |
4 | Emily | HR | 7000 |
5 | Ryan | R&D | 13000 |
… | … | … | … |
【SPL 指令碼】
|
A | B |
1 | =file("Employee.txt").cursor@t() | /產生僱員表的遊標 |
2 | =A1.groups(Department; top(-3;Salary):Top3) | /按部門分組並取出每組薪水前三的記錄 |
3 | =A2.conj(Top3) | /把各部門薪水前三的記錄合併 |
《 》中還有更多相關計算示例。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69957599/viewspace-2733162/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料的運算(上)
- 大資料計算:結構化大資料計算的理想模式大資料模式
- 【資料結構與演算法】位運算資料結構演算法
- 結構化資料、半結構化資料和非結構化資料
- 結構化資料與非結構化資料的差異
- 資料庫結構的優化資料庫優化
- 資料結構之連結串列【上】資料結構
- 什麼是結構化資料?什麼是半結構化資料?
- Redis資料結構及物件(上)Redis資料結構物件
- 可持久化資料結構持久化資料結構
- Flink使用二次聚合實現TopN計算-亂序資料
- 資料結構第九節(排序(上))資料結構排序
- Oracle 資料庫體系結構 (上)Oracle資料庫
- 資料結構最佳化DP資料結構
- 可持久化資料結構1持久化資料結構
- Spark效能優化:優化資料結構Spark優化資料結構
- 【資料結構】30、hashmap=》hash 計算方式資料結構HashMap
- 括號匹配檢驗 資料結構運用資料結構
- 資料結構與演算法-連結串列(上)資料結構演算法
- 資料結構 (計算機儲存、組織資料方式)資料結構計算機
- 透過結構化資料構建頁面
- python字典和結構化資料Python
- LoRa資料包結構分析及資料傳輸時間的計算
- 【Immutable.js】可持久化資料結構以及結構分享JS持久化資料結構
- Flink實時計算topN熱榜
- 大資料的運算加減乘除大資料
- 【資料結構篇】認識資料結構資料結構
- Python-資料運算Python
- 不同型別資料運算型別
- 【資料結構】二叉樹的線索化!!資料結構二叉樹
- 視覺化的資料結構和演算法視覺化資料結構演算法
- [大資料量]java移位運算與位運算與資料型別的儲存大資料Java資料型別
- C++資料結構和pb資料結構的轉換C++資料結構
- redis的資料結構Redis資料結構
- cats 的資料結構資料結構
- database資料庫的資料結構Database資料庫資料結構
- 什麼是非結構化資料(unstructured data)?Struct
- 資料結構 中綴表示式轉化資料結構