MaxCompute公開數據集簡介
目前阿里雲MaxCompute已經免費向全部用戶開放了多種公用數據集,包括:
- 股票價格數據
- 房產信息
- 影視及其票房數據
- TPC-DS數據集
這些公開數據現已免費開放給用戶,並已經完成了數據分析前序較複雜的數據獲取、上傳、清洗等過程,可以直接進入數據分析階段。因此可以直接使用這些數據集來進行一定的MaxCompute的學習以及數據的分析過程。具體的MaxCompute公開數據集介紹見:阿里雲MaxCompute(大數據)公開數據集---帶你玩轉人工智能。
公開數據集開發環境
爲了使用上述的公開數據集,需要進行如下的步驟:
1. 獲取權限
所有的數據均被存儲在MaxCompute 產品中的public_data 項目空間中。首先,需要以項目空間的owner 或者管理員的身份,在自己的項目空間下,執行如下操作。執行完成後用戶項目空間下的所有成員均可讀取各公開數據集合。
add user ALIYUN$everyone;
2. 使用public_data項目空間下的表
用戶需要跨項目空間訪問數據,在數據工場中編輯SQL 時,必須在表明前指定項目名稱,例如:
select * from public_data.ods_enterprise_share_basic where ds = '20170114';
3. MaxCompute Studio開發環境
下面對public_data中公開數據集的操作主要使用MaxCompute Studio開發環境,具體的開發環境搭建見前序文章:MaxCompute基礎開發環境搭建 。
影視及票房數據集簡介
該公開數據集是所有公開數據集中結構和內容較簡單的一個,其中包括的數據信息爲:每日更新國內影視劇信息及票房數據信息 (後續會發現其實該數據集中的內容沒有持續更新)。具體介紹如下:
項目 | public_data |
表集合 |
dwd_product_movie_basic_info 電影基本信息 ods_product_movie_box 票房基本信息 |
更新週期 | 每日早10 點前更新。至2016 年12 月13 日開始更新,全量更新(這裏是官方的介紹,但實際內容好像有所出入,後面後進行查看) |
查詢示例 | select * from public_data.dwd_product_movie_basic_info where ds ='20170112' limit 10; |
dwd_ product_ movie_ basic_ info表結構
字段英文名 |
字段類型 |
描述 |
是否是分區列 |
movie_ name |
STRING |
電影名稱 |
|
dirctor |
STRING |
導演 |
|
scriptwriter |
STRING |
編劇 |
|
area |
STRING |
製片地區/國家 |
|
actors |
STRING |
主演 |
|
type |
STRING |
類型 |
|
movie_ length |
STRING |
電影長度 |
|
movie_ date |
STRING |
上映日期 |
|
movie_ language |
STRING |
語言 |
|
imdb_ url |
STRING |
imdb號 |
|
ds |
STRING |
日期 |
分區列 |
ods_product_movie_box表結構
字段英文名 |
字段類型 |
描述 |
是否是分區列 |
rank |
STRING |
排名 |
|
avgprice |
STRING |
平均票價 |
|
avppeople |
STRING |
場均人次 |
|
boxoffice |
STRING |
單日票房(萬) |
|
boxoffice_ up |
STRING |
環比變化 (%) |
|
irank |
STRING |
排名 |
|
movieday |
STRING |
上映天數 |
|
moviename |
STRING |
影片名 |
|
sumboxoffice |
STRING |
累計票房(萬) |
|
womindex |
STRING |
口碑指數 |
|
ds |
STRING |
日期 |
分區列 |
影視及票房數據集SQL實戰
瞭解完該數據集的大致內容,下面使用MaxCompute SQL來初步探索一下這個數據集的內容。
查詢dwd_product_movie_basic_info表
查看電影基本信息表的記錄起止時間
由於dwd_product_movie_basic_info使用ds(日期列)來作爲分區信息,因此查看該表的分區信息就可以獲得整個數據集數據記錄的起止時間,命令如下;
show partitions public_data.dwd_product_movie_basic_info;
返回結果如下:
ds=20161227
ds=20170112
ds=20170113
ds=20170114
ds=20170115
ds=20170116
...
ds=20170629
ds=20170630
ds=20170701
ds=20170702
ds=20170703
ds=20170704
ds=20170705
因此可以看到該數據集的開始記錄的時間爲20161227,然後再從20170112開始進行每天連續增量更新直到20170705。此後則沒有繼續進行數據的更新。
所以對該表進行查詢過程中,查詢的日期範圍應該在這個時間返回內,否則無數據返回。引入使用如下命令查詢今天的電影信息則是沒有數據的:
-- 無該分區數據
select * from public_data.dwd_product_movie_basic_info where ds ='20190201' limit 10;
查詢每日上映電影數量
dwd_product_movie_basic_info表中使用ds作爲分區,下面統計每個分區(每天)記錄的電影數量:
-- 統計每天電影記錄的總數量
select ds, count(*) as ds_count from public_data.dwd_product_movie_basic_info group by ds;
返回結果如下:
ds ds_count
+---+---------+
20170112 359927
20170113 360347
20170114 360693
20170115 360905
20170116 360905
20170117 361159
20170118 361545
20170119 361727
...
20170629 379581
20170630 379581
20170701 379581
20170702 379581
20170703 379581
20170704 379581
20170705 379581
這裏可以看到每天的電影記錄數量有30多萬條,想想一天內會有那麼多電影上映嗎?對這個數量有些疑惑,可以使用如下命令來驗證對所有時間的記錄數進一步統計,並與數據表的所有記錄數量進行對比,來驗證這裏的統計結果。
首先來對上述的結果進行進一步的統計:
-- 每天電影記錄數量的真實性,對所有的求和彙總
select sum(tmp.count) as total_num from (
select ds, count(*) as count from public_data.dwd_product_movie_basic_info group by ds
) tmp;
然後在查詢該表中所有記錄的數量:
-- 統計該表中的數據總數
select count(*) from public_data.dwd_product_movie_basic_info;
兩者返回的結果均爲:
65430458
因此,可以看出來上述的按日期對電影數量的統計結果並沒有問題,但每天有30多萬的電影上映還是不太相信啊,畢竟對公開數據集的介紹裏說的這是國內的數據量。帶着這個疑問,我們來查看某一個日期的電影信息:
-- 查詢20170304分區中的10條數據
select * from public_data.dwd_product_movie_basic_info where ds ='20170304' limit 10;
返回結果如下:
可以看到這裏ds並不是電影上映的時間,而是數據進行分區記錄的時間,因此根據ds查詢的話,很多記錄的電影數據實際上是已經上映過的,因此這裏的數據那麼龐大就可以理解了。
根據電影上映日期進行查詢
通過上面的查詢可以看到ds分區列不是電影上映的時間,而是數據記錄的時間。因此可以根據電影上映時間對數據進行一些查詢。例如如下幾個查詢:
1. 查詢1990年到2020年,上映日期最近的20個的英文記錄片電影:
-- 查詢1990年到2020年,上映日期最近的20個的英文記錄片電影
select distinct *
from public_data.dwd_product_movie_basic_info
where movie_language='英文'
and type='紀錄片'
and movie_date between '1990-01-01' and '2020-01-01'
order by movie_date desc
limit 20;
這裏是一般的查詢方式,得到的結果如下;
可以看到這裏其實只是一條數據, 而distinct去重語句沒有生效的原因是,distinct根據所有列進行去重,而這裏數據的ds不同,因此去重不掉。而這裏在不同ds存在相同電影信息的原因是:一個電影具有一定的上映時間範圍,例如電影A從201901月上映到201906月下映,因此這段時間返回內,不同時間(ds)均有這個電影的記錄。
爲了去重這裏的數據,這裏可以將ds列從distinct中去除後進行重新查詢:
-- 查詢1990年到2020年,上映日期最近的20個的英文記錄片電影(去重需要過濾掉ds)
select distinct movie_name, dirctor, scriptwriter, area, actors, type, movie_length, movie_date, movie_language, imdb_url
from public_data.dwd_product_movie_basic_info
where movie_language='英文'
and type='紀錄片'
and movie_date between '1990-01-01' and '2020-01-01'
order by movie_date desc
limit 20;
得到的結果發現只有一條數據:
看來這個數據集中的記錄其實還是有一定問題的。
2. 查詢1990年到2020年,上映日期最近的20箇中文電影,並且除imdb_url可爲空之外,其他字段都不能爲空:
-- 查詢1990年到2020年,上映日期最近的20箇中文電影,並且除imdb_url可爲空之外,其他字段都不能爲空
select distinct movie_name, dirctor, scriptwriter, area, actors, type, movie_length, movie_date, movie_language
from public_data.dwd_product_movie_basic_info
where movie_language='中文'
and scriptwriter is not null and actors is not null and type is not null and movie_length is not null
and movie_date between '1990-01-01' and '2020-01-01'
order by movie_date desc
limit 20;
返回結果如下,看來滿足條件的數據只有19個:
查詢ods_product_movie_box表
查看票房記錄表中數據的起止日期
show partitions public_data.ods_product_movie_box;
返回結果如下:
ds=20170113
ds=20170114
ds=20170115
ds=20170116
ds=20170117
ds=20170118
ds=20170119
ds=20170120
ds=20170121
...
ds=20170801
ds=20170802
ds=20170803
ds=20170805
ds=20170806
ds=20170807
ds=20170808
ds=20170809
ds=20170810
ds=20170812
可以看到ods_product_movie_box表中的記錄開始於20170113,終止於20170812。記錄除最後一天外,均是每日連續記錄。但該表的記錄和dwd_product_movie_basic_info表中的記錄,在日期方面並不是在一個時間範圍內。
統計每天具有票房的電影記錄數
--查看每天有多少記錄了票房的電影
select ds, count(*) as ds_count from public_data.ods_product_movie_box group by ds;
返回結果如下:
ds ds_count
+---+----+
20170113 10
20170114 10
20170115 10
20170116 10
20170117 10
20170118 10
20170119 10
...
20170803 10
20170805 10
20170806 10
20170807 10
20170808 10
20170809 10
20170810 10
20170812 10
可以看到每天電影票房的記錄只記錄排名前10的電影。可以查看某一天的電影票房數據如下:
select * from public_data.ods_product_movie_box where ds='20170115';
返回結果如下:
統計電影票房
1. 統計每日電影累計總票房
--查看每天(每分區)上映電影的總票房
select ds, sum(sumboxoffice) as totol_box from public_data.ods_product_movie_box group by ds;
返回結果如下:
ds totol_box
+---+----------+
20170113 254059.0
20170114 262496.0
20170115 274466.0
20170116 324493.0
20170117 333592.0
20170118 335652.0
20170119 300577.0
20170120 280885.0
20170121 351980.0
20170122 361073.0
...
20170802 390234.0
20170803 323639.0
20170805 396451.0
20170806 376678.0
20170807 497773.0
20170808 534007.0
20170809 458423.0
20170810 480300.0
20170812 534594.0
2. 統計每日電影單日總票房
--單日總票房
select ds, sum(boxoffice) as daily_total_box from public_data.ods_product_movie_box group by ds;
返回結果如下:
ds daily_total_box
+---+----------------+
20170113 1158.0
20170114 1032.0
20170115 570.0
20170116 414.0
20170117 431.0
20170118 492.0
20170119 465.0
20170120 624.0
20170121 401.0
20170122 380.0
...
20170802 4650.0
20170803 2083.0
20170805 1310.0
20170806 82.0
20170807 385.0
20170808 438.0
20170809 752.0
20170810 5154.0
20170812 1017.0
3. 統計2017前半年,單日總票房最高的十天。
select ds, sum(boxoffice) as daily_total_box
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by ds
order by daily_total_box desc
limit 10;
返回結果如下:
根據票房信息進行查詢
1. 查詢2017年前半年累計票房最高的10個電影:
-- 查詢2017年前半年累計票房最高的10個電影
select distinct *
from (select * from public_data.ods_product_movie_box where ds between '20170101' and '20170630') tmp
order by sumboxoffice desc
limit 10;
返回結果如下:
這裏可以看到數據並沒有嚴格的根據sumboxoffice字段進行降序排序,具體的原因:是因爲這裏的sumboxoffice字段的類型爲string,因此在對其進行排序時,是根據字符串的字典序進行排序的,而不是數值的大小。
分析該表的數據可知,該表中的記錄是每個電影在上映時間範圍內的每天的數據信息,因此如果需要查找2017年前半年累計票房最高的10個電影,需要根據電影名稱進行分組查詢。同時修復上面的字符串數組排序問題,命令如下:
-- 查詢2017年前半年累計票房最高的10個電影(子查詢中沒有對sumboxoffice進行類型轉換)
select distinct tmp.moviename, cast(tmp.max_sumboxoffice as bigint) as sumboxoffice_num, tmp.max_ds as end_time
from (
select moviename, max(sumboxoffice) as max_sumboxoffice, max(ds) as max_ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by moviename
) tmp
order by sumboxoffice_num desc
limit 10;
返回結果如下:
但上述查詢的子查詢中沒有注意sumboxoffice的類型轉換問題, 下面在子查詢中加上max(cast(sumboxoffice as bigint))的強制類型轉換,並且去掉外層查詢的類型轉換:
-- 查詢2017年前半年,累計票房最高的10個電影(注意數據類型轉換)
select distinct tmp.moviename, tmp.max_sumboxoffice as sumboxoffice_num, tmp.max_ds as end_time
from (
select moviename, max(cast(sumboxoffice as bigint)) as max_sumboxoffice, max(ds) as max_ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by moviename
) tmp
order by sumboxoffice_num desc
limit 10;
返回結果如下,這纔是正確的查詢結果:
2. 查詢2017年前半年,單日票房最高的10個電影。(這裏不根據天來計算,例如某天單日票房第二高的電影A的票房,大於第二天單日票房第一高的電影B,那麼A依然被包含在結果集中,並且排序在B之前),命令如下:
select distinct moviename, cast(boxoffice as bigint) as max_boxoffic, ds
from (
select * from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
) tmp
order by max_boxoffic desc
limit 10;
返回結果如下:
例如這裏大鬧天竺在20170127單日票房中排名第2,但它的單日票房大於20170622排名第一的變形金剛5,此時大鬧天竺仍然在結果集中,並且排名在變形金剛5之前。
此外,此時的查詢結果仍然有一個問題,就是排名中有重複排名的電影。這是由於變形金剛5分別在20170622,23,24三天均排名第一,因此該電影在排行榜中出現了三次。
3. 查詢2017年前半年,每天單日票房最高的10個電影。
這裏的單日最高,是統計前半年中每日票房最高的10個電影,以及所在的日期。不同於上面的查詢,此時就不允許日期具有重複了,也就是每天中只能選取具有最高票房的一個電影參與排序。此時需要對ods_product_movie_box表進行自關聯的聯合查詢。命令如下,其中子查詢是根據ds進行分組,找到每日的最大單日票房max_boxofffice和對應的ds,然後外層查詢將子查詢作爲一個表,對ods_product_movie_box自身進行join操作,連接的條件便是單日票房max_boxofffice和對應的ds,最後得到查詢結果。
-- 查詢2017年前半年,每天單日票房最高的10個電影(需要根據天(ds)分組)
select distinct t1.moviename, t2.max_boxoffice as max_boxoffice_num, t2.ds
from public_data.ods_product_movie_box as t1
join (
select max(cast(boxoffice as bigint)) as max_boxoffice, ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by ds
) t2 on t1.ds=t2.ds and t1.boxoffice=t2.max_boxoffice
ORDER by max_boxoffice_num desc
limit 10;
返回結果如下:
可以看到此時,ds沒有重複的數據,並且“變形金剛5”仍然是佔據了20170622-24三天的最高單日票房。
4. 查詢2017年前半年平均票價最高的10個電影。
這裏的查詢思路與上述類似,由於是找到平均票價最高的10個電影,而票房記錄中存在一個電影的多個每日票價,因此這裏還是需要根據moviename維度來進行去重。子查詢根據moviename維度來查找平均票價最高的moviename和對應的max_avgprice,然後外層查詢進行join來查詢對應的moivename的上映日期,最後進行排序。
-- 查詢2017年前半年平均票價最高的10個電影
select t1.moviename, t1.max_avgprice, t2.ds
from (
select moviename, max(cast(avgprice as bigint)) as max_avgprice
from public_data.ods_product_movie_box
group by moviename
) as t1
join public_data.ods_product_movie_box as t2
on t1.moviename=t2.moviename and t1.max_avgprice=t2.avgprice
where ds between '20170101' and '20170630'
order by max_avgprice desc
limit 10;
返回結果如下:
5. 查詢2017年前半年上映時間最長的10個電影。
這裏同樣需要使用子查詢,根據moviename進行分組得到moviename,max_movieday和min_ds(電影開始的上映時間),然後在通過外查詢進行排序。
-- 查詢2017年前半年上映時間最長的10個電影
select moviename, tmp.max_movieday as max_movieday_num, min_ds as start_ds
from (
select moviename, max(cast(movieday as bigint)) as max_movieday, min(ds) as min_ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by moviename
) tmp
order by max_movieday_num desc
limit 10;
返回結果如下:
這裏的上映時長有點不可思議啊, 暫時不知道是否是數據有問題。
6. 統計2017年上半年,上座率最高的10部電影。
-- 統計2017年上半年,上座率最高的10部電影
select t1.moviename, t1.max_avppeople, t2.ds, t2.movieday, t2.rank, t2.avgprice, t2.boxoffice
from (
select moviename, max(cast(avppeople as bigint)) as max_avppeople
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630'
group by moviename
) t1
join public_data.ods_product_movie_box t2 on t1.moviename=t2.moviename and t1.max_avppeople=t2.avppeople
order by max_avppeople desc
limit 10;
得到的結果如下:
從返回的數據中可以看到,這裏上座人數最多的movieday很多都是負值,這裏大致猜測一下,應該是電影的未正式上映前的點映階段。例如這裏面比較熟悉的“銀河護衛隊2”,在點映階段的上座率最高,並且票價也很高。好奇看一下該電影的票房變化信息:
select moviename, movieday, rank, avgprice, avppeople, boxoffice, boxoffice_up, sumboxoffice, ds
from public_data.ods_product_movie_box
where moviename='銀河護衛隊2'
order by ds
limit 100;
返回結果如下:
可以看到,該電影是在0501日點映,然後在五一黃金週拿到了不少的票房,在黃金週過去後票房開始回落。
查詢一個電影的每日票房信息變化
上述已經查詢了“銀河護衛隊2”的票房變化情況,下面查詢另一個電影(“乘風破浪”)從上映到下映之間的每日票房變化:
-- 查詢一個電影從上映到下映之間的每日票房變化
select moviename, movieday, rank, boxoffice, sumboxoffice, ds
from public_data.ods_product_movie_box
where moviename='乘風破浪'
order by ds
limit 100;
返回結果如下:
可以看到該電影一共上映了35天,從上映第一天到下映這個範圍單日排名變化、平均票價,場均人次,每日票房變化、票房浮動、以及累計票房變化。這樣就可以根據ds時間維度來進行一些數據可視化的工作。
電影信息表和票房表聯合查詢
查詢兩個表公有的數據
1. 查詢包含在兩個表中的電影數據的10條記錄:
-- 查詢包含在兩個表中的電影數據的10條記錄
select distinct movie_name, dirctor, scriptwriter, area, actors, type, movie_length, movie_date, movie_language
from public_data.dwd_product_movie_basic_info as t1
join public_data.ods_product_movie_box as t2 on t1.movie_name=t2.moviename
limit 10;
返回結果如下:
2. 查詢2017年前半年,累計票房最高的10個電影,並查看上映日期。
上面已經通過表ods_product_movie_box進行了該查詢的前半部分“查詢2017年前半年,累計票房最高的10個電影”,後面的電影上映時間則是需要在dwd_product_movie_basic_info表中獲取。因此這裏需要進行兩個表的join操作。
容易想到的是使用之前的查詢作爲子查詢,來join dwd_product_movie_basic_info表獲取movie_date即可,命令如下:
-- 查詢2017年前半年,累計票房最高的10個電影,並查看上映日期(存在影片重複)
select distinct t1.moviename, t1.sumboxoffice_num, t1.end_time, t2.movie_date
from (
select distinct tmp.moviename, tmp.max_sumboxoffice as sumboxoffice_num, tmp.max_ds as end_time
from (
select moviename, max(cast(sumboxoffice as bigint)) as max_sumboxoffice, max(ds) as max_ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630' group by moviename) tmp
order by sumboxoffice_num desc
limit 10
) t1
left join public_data.dwd_product_movie_basic_info as t2 on t1.moviename=t2.movie_name
order by t1.sumboxoffice_num desc
limit 10;
但此時得到的查詢結果爲:
可以看到最後的乘風破浪由於在 dwd_product_movie_basic_info表中存在多條記錄,因此這裏join之後會出現影片的重複。
爲了去掉dwd_product_movie_basic_info表中相同影片重複的記錄,需要對dwd_product_movie_basic_info表進行處理後在進行join操作:
-- 查詢2017年前半年,累計票房最高的10個電影,並查看上映日期(完整)
select distinct t1.moviename, t1.sumboxoffice_num, t1.end_time, t2.movie_date
from (
select distinct tmp.moviename, tmp.max_sumboxoffice as sumboxoffice_num, tmp.max_ds as end_time
from (
select moviename, max(cast(sumboxoffice as bigint)) as max_sumboxoffice, max(ds) as max_ds
from public_data.ods_product_movie_box
where ds between '20170101' and '20170630' group by moviename) tmp
order by sumboxoffice_num desc
limit 10
) t1
left join (
select movie_name, max(movie_date) as movie_date
from public_data.dwd_product_movie_basic_info
group by movie_name
) as t2 on t1.moviename=t2.movie_name
order by t1.sumboxoffice_num desc
limit 10;
得到的正確查詢結果如下:
可以看到,此時的查詢結果去除了影片的重複,得到了正確的結果。此時也可以發現, dwd_product_movie_basic_info表中的影片數據其實不是很全面,很多影片的move_date字段都是缺失的,這應該是數據集在進行數據收集時的問題。
結語
上面對MaxCompute的公開數據集--電影及票房數據,進行了各種的SQL查詢。內容包括了比較常用的一些查詢過程,但仍可以使用更多的SQL來進行其他方面或維度的數據分析,有興趣的讀者可以繼續進行完善。
此外,MaxCompute還公開了其他的數據集供開發使用,這裏僅是選取了較爲簡單的一個。並且從上面的查詢過程可以看出,該數據集中特別是dwd_product_movie_basic_info表中的數據,並不是很完整,可能是數據獲取和清理時有一定的缺失,可以嘗試在其他公開數據集中進行更加深入的處理和分析操作。