- Spark大數據商業實戰三部曲:內核解密|商業案例|性能調優
- 王家林
- 1947字
- 2019-12-12 17:30:07
12.3 通過RDD分析各種類型的最喜愛電影TopN及性能優化技巧
通過RDD分析大數據電影點評系統各種類型的最喜愛電影TopN。本節分析最受男性喜愛的電影Top10和最受女性喜愛的電影Top10。
評級文件ratings.dat的格式描述如下。
1. UserID::MovieID::Rating::Timestamp 2. 用戶ID、電影ID、評分數據、時間戳
用戶文件users.dat的格式描述如下。
1. UserID::Gender::Age::Occupation::Zip-code 2. 用戶ID、性別、年齡、職業、郵編代碼
單單從評分數據ratings中無法計算出最受男性或者女性喜愛的電影Top10,因為該RDD中沒有性別Gender信息,如果需要使用性別Gender信息進行性別Gender的分類,此時一定需要聚合。當然,我們力求聚合的使用是mapjoin(分布式計算的殺手是數據傾斜,Mapper端的Join是一定不會數據傾斜的),這里可否使用mapjoin呢?不可以,因為用戶的數據非常多!所以,這里要使用正常的Join,此處的場景不會數據傾斜,因為用戶一般都均勻地分布。
最受男性喜愛的電影Top10和最受女性喜愛的電影Top10分析需注意以下事項。
(1)因為要再次使用電影數據的RDD,所以復用了前面Cache的ratings數據。
(2)在根據性別過濾出數據后,關于TopN部分的代碼直接復用前面的代碼就行了。
(3)要進行Join,需要key-value。
(4)在進行Join的時候,通過take等方法注意Join后的數據格式(3319,((3319, 50, 4.5),F))。
(5)使用數據冗余來實現代碼復用或者更高效地運行,這是企業級項目的一個非常重要的技巧!
大數據電影點評系統中,統計最受男性喜愛的電影Top10和最受女性喜愛的電影Top10,我們先分別過濾出男性、女性相關的數據,具體實現思路如下:
(1)對ratings中的(用戶ID,電影ID,評分)元組進行map轉換,格式化成Key-Value,即(用戶ID,(用戶ID,電影ID,評分))。
(2)對usersRDD中的每行數據按"::"分隔符分割,然后進行map轉換,格式化成Key-Value,即(用戶ID,性別)。
(3)將(用戶ID,(用戶ID,電影ID,評分))與(用戶ID,性別)進行Join生成新的genderRatings RDD。格式為:(用戶ID,((用戶ID,電影ID,評分),性別)),性別,并且進行Cache緩存。
(4)對genderRatings RDD進行過濾轉換,從元組(x._1用戶ID,(x._2._1(用戶ID,電影ID,評分),x._2._2性別))過濾出x._2._2性別等于男性的數據。然后進行map轉換為x._2._1,即轉換成(用戶ID,電影ID,評分)格式,生成maleFilteredRatings。
(5)對genderRatings RDD進行過濾轉換,從元組(x._1用戶ID,(x._2._1(用戶ID,電影ID,評分),x._2._2性別))過濾出x._2._2性別等于女性的數據。然后進行map轉換為x._2._1,即轉換成(用戶ID,電影ID,評分)格式,生成femaleFilteredRatings。
從大數據電影點評系統中過濾男性、女性相關的數據的代碼如下。
1. val male = "M" 2. val female = "F" 3. val genderRatings = ratings.map(x => (x._1, (x._1, x._2, x._3))).join( 4. usersRDD.map(_.split("::")).map(x => (x(0), x(1)))).cache() 5. genderRatings.take(2).foreach(println) 6. val maleFilteredRatings: RDD[(String, String, String)] = gender Ratings.filter(x => x._2._2.equals("M")).map(x => x._2._1) 7. val femaleFilteredRatings = genderRatings.filter(x => x._2._2.equals ("F")).map(x => x._2._1)
在IDEA中運行代碼,打印出genderRatings的數據,取10個數據,格式為:(用戶ID,((用戶ID,電影ID,評分),性別)),結果如下。
1. (3319,((3319,32,5),F)) 2. (3319,((3319,50,4.5),F)) 3. (3319,((3319,163,4.5),F)) 4. (3319,((3319,180,5),F)) 5. (3319,((3319,296,5),F)) 6. (3319,((3319,318,5),F)) 7. (3319,((3319,405,4),F)) 8. (3319,((3319,914,4.5),F)) 9. (3319,((3319,1088,4),F)) 10. (3319,((3319,1136,5),F))
電影點評系統用戶行為分析,統計所有電影中最受男性喜愛的電影Top10,具體實現思路如下:
(1)將性別為男的用戶過濾以后的數據(用戶ID,電影ID,評分)進行map轉換,格式化成為Key-Value的方式,即(電影ID,(評分,1))。
(2)使用reduceByKey算子對Value值進行匯聚轉換,對兩個具有相同Key值,而Value不同的元組,如(電影ID,(x.評分,x.1)),(電影ID,(y.評分,y.1)),計算得出(x的評分+y的評分,x的計數+y的計數),轉換以后Key是電影ID,Value是(總的評分,總的點評人數),格式化成為Key-Value,即(電影ID,(總評分,總點評人數))。
(3)reduceByKey算子執行完畢,接下來進行map轉換操作,交換Key-Value值,并且計算出電影平均分=總評分/總點評人數,即將(電影ID,(總評分,總點評人數))轉換成((總評分/總點評人數),電影ID),然后使用sortByKey(false)算子按電影平均分降序排列。
(4)再次進行Key和Value的交換,打印輸出。使用map轉換函數將((總評分/總點評人數),電影ID)進行交換,轉換為(電影ID,(總評分/總點評人數)),再通過take(10)算子獲取所有電影中最受男性喜愛的電影Top10,進行打印輸出。
在所有電影中分析最受男性喜愛的電影Top10的代碼如下。
1. println("所有電影中最受男性喜愛的電影Top10:") 2. maleFilteredRatings.map(x=>(x._2,(x._3.toDouble, 1)))//格式化成為Key-Value 3. .reduceByKey((x, y) => (x._1 + y._1,x._2 + y._2)) //對Value進行reduce操作,分別得出每部電影的總的評分和總的點評人數 4. .map(x => (x._2._1.toDouble / x._2._2, x._1)) //求出電影平均分 5. .sortByKey(false) //降序排列 6. .map(x => (x._2, x._1)) 7. .take(10) //取Top10 8. .foreach(println) //打印到控制臺
在IDEA中運行代碼,結果如下。
1. 所有電影中最受男性喜愛的電影Top10: 2. (855,5.0) 3. (6075,5.0) 4. (1166,5.0) 5. (3641,5.0) 6. (1045,5.0) 7. (4136,5.0) 8. (2538,5.0) 9. (7227,5.0) 10. (8484,5.0) 11. (5599,5.0)
同樣地,在電影點評系統用戶行為分析中,我們可以統計所有電影中最受女性喜愛的電影Top10,具體實現思路和最受男性喜愛的電影Top10類似,這里不再贅述。
從所有電影中分析最受女性喜愛的電影Top10的代碼如下。
1. println("所有電影中最受女性喜愛的電影Top10:") 2. femaleFilteredRatings.map(x=>(x._2,(x._3.toDouble,1)))//格式化成為Key-Value 3. .reduceByKey((x, y) => (x._1 + y._1,x._2 + y._2)) //對Value進行reduce操作,分別得出每部電影的總的評分和總的點評人數 4. .map(x => (x._2._1.toDouble / x._2._2, x._1)) //求出電影平均分 5. .sortByKey(false) //降序排列 6. .map(x => (x._2, x._1)) 7. .take(10) //取Top10 8. .foreach(println) //打印到控制臺
在IDEA中運行代碼,結果如下。
1. 所有電影中最受女性喜愛的電影Top10: 2. [Stage 43:=================================> 7 + 1) / 8](789,5.0) 3. (855,5.0) 4. (32153,5.0) 5. (4763,5.0) 6. (26246,5.0) 7. (2332,5.0) 8. (503,5.0) 9. (4925,5.0) 10. (8767,5.0) 11. (44657,5.0)