在外存中實現分組的代碼示例

   在數據分析中,我們經常需要將數據分組,然後計算出各組的彙總值,或者在各組中分別計算。集算器中,可以用groups函數計算數據的分組彙總結果,更可以用group函數將表中記錄分成多組,以便後續計算。但是,如果需要排序的數據量巨大,情況就不同了,這時是不能一次將它們讀入內存的,這樣普通的分組彙總,或者分組的方法就無法執行了,此時就可能需要使用外存分組。

  下面,先來準備一個大數據表,簡單模擬1,000,000條手機用戶的通話時長記錄,存儲在二進制文件PhoneBill中:



 

   其中,電話號碼使用8位整數,前4位固定爲1234,後4位隨機生成。通話開始時間在2014年8月中隨機產生。通話時長爲整數,也隨機生成,產生時使通話時長有90%的可能性爲1分鐘,最長20分鐘。數據文件完成後,在B11中讀出前1000條如下:



 

  現在,需要根據PhoneBill中的數據計算:

  ① 8月中每天所有用戶的總通話時長以及每次通話的平均時長。

  ② 每位用戶在8月的通話時長。

  ③ 分別將每天的通話記錄存儲到文件中。

  ④ 8月的每一天中,通話總時長最多的5位用戶號碼。

  先來看問題①,這首先需要將所有的訂單數據按日期來分組彙總。因爲8月一共只有31天,所以結果集並不是大數據,可以直接在內存中彙總計算:



 

   A2用A1中的二進制文本數據生成遊標。A3計算遊標中數據的分組彙總結果如下:



 

   因爲結果本身的數據量並不大,計算分組彙總時,其實只需要將遊標中的數據遍歷一次,並不需要外存分組,直接用groups函數就能計算。這裏的結果集並不龐大,可以直接獲得結果,並不需要使用遊標。計算每天中,每次通話的平均時間,需要先統計出每天的通話總時間及總次數,再進一步計算出平均通話時間,A4中獲得的結果如下:



 

   問題②中的情況就不同了,由於用戶量要比8月的天數多得多,這時就需要考慮分組彙總的結果是不是能一次返回到內存中。在這裏,最多隻有10,000個用戶,並不算太多,只是以此來說明大數據結果集的計算情況。計算時,假設內存中只能容納1000條記錄:



 

   在計算大數據分組彙總結果時,需要用groupx函數,利用外存,根據設定的緩衝區行數來將遊標內的數據逐步讀出分組。A3中,計算遊標中數據,按Phone分組;彙總計算總通話時長的結果,同時設定緩衝區行數爲1000。大數據分組彙總的結果是遊標,讀取數據的方法和普通的遊標完全相同。A3中的結果如下:



 

   在A4中讀出了前1000名用戶的總通話時長結果:



 

   另外,遊標中的數據如果沒有全部讀完,需要調用cs.close()函數,以及時清理外存臨時文件。

   問題③需要先將數據按照日期分組,再將每天的數據存儲到文件中:



 

   使用groupn函數的大數據分組和普通的分組不同,需要在分組表達式中直接指定組號,在A3中,用訂單日期的“日”作爲組號。A3的函數中計算的結果與前面的分組彙總不同,返回的是遊標序列,每個分組對應1個遊標:



 

   在第4、5行的代碼中,將每天的遊標數據分別存到文件中。在A6中,選擇了其中4日的數據,在A7中讀出了前1000條記錄如下:



 

   問題④仍然將數據按照日期分組,再在每個分組中執行分組彙總,最後根據彙總結果選出所需的用戶號碼:



 

   A3中,仍然在分組表達式中直接指定“日”作爲組號,分組時返回的仍然是遊標的序列:



 

   第4行到第6行的代碼循環每個分組的遊標數據,分別彙總每個用戶每天的總通話時間,並根據彙總結果再次彙總出通話時間排在前5名的用戶信息。需要注意的是,用匯總函數topx計算降序排序時,在排序表達式前加負號即可,如B5中的-TotalDuration。在結果中,選出通話時間最長的5個號碼數據,並存入B3的序表中。循環完畢後,可以從B3中讀出最終的結果如下:



 

   除了將總的話費數據分組,也可以繼續使用問題③中生成的文件數據來處理這個問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章