大數據雲計算——實時推薦系統的設計到代碼實現和源碼下載

基於大數據與機器學習算法的推薦系統設計

項目源代碼:https://github.com/2462612540/Big_Data_Spark_Scala_hadoop/tree/master/Movie_recommendation_system

第1章項目體系架構設計

1.1 項目系統架構

項目以推薦系統建設領域知名的經過修改過的 MovieLens 數據集作爲依託,以某科技公司電影網站真實業務數據架構爲基礎,構建了符合教學體系的一體化的電影推薦系統,包含了離線推薦與實時推薦體系,綜合利用了協同過濾算法以及基於內容的推薦方法來提供混合推薦。提供了從前端應用、後臺服務、算法設計實現、平臺部署等多方位的閉環的業務實現。

用戶 可視化: 主要負責實現和用戶的交互以及業務數據的展示,主體採用AngularJS2 進行實現, 部署在 tomcat服務上。

綜合業務服務: 主要實現 JavaEE 層面整體的業務邏輯,通過 Spring 進行構建,對接業務需求。部署在 Tomcat 上。

【 數據存儲部分】

業務數據庫: 項目採用廣泛應用的文檔數據庫 MongDB 作爲主數據庫, 主要負責平臺業務邏輯數據的存儲。

搜索服務器: 項目愛用 ElasticSearch 作爲模糊檢索服務器, 通過利用 ES 強大的匹配查詢能力實現基於內容的推薦服務。

緩存數據庫: 項目採用 Redis 作爲緩存數據庫, 主要用來支撐實時推薦系統部分對於數據的高速獲取需求。

【離線推薦部分】
離線統計服務: 批處理統計性業務採用 Spark Core + Spark SQL 進行實現,實現對指標類數據的統計任務。

離線推薦服務: 離線推薦業務採用 Spark Core + Spark MLlib 進行實現, 採用ALS 算法進行實現。

工作調度服務: 對於離線推薦部分需要以一定的時間頻率對算法進行調度, 採用 Azkaban 進行任務的調度。

【實時推薦部分】

日誌採集服務: 通過利用 Flume-ng 對業務平臺中用戶對於電影的一次評分行爲進行採集, 實時發送到 Kafka 集羣。
消息緩衝服務: 項目採用 Kafka 作爲流式數據的緩存組件, 接受來自 Flume 的數據採集請求。 並將數據推送到項目的實時推薦系統部分。
實時推薦服務: 項目採用 Spark Streaming 作爲實時推薦系統, 通過接收 Kafka中緩存的數據, 通過設計的推薦算法實現對實時推薦的數據處理, 並將結構合併更新到 MongoDB 數據庫

1.2 項目數據流程

【系統初始化部分】
0. 通過 Spark SQL 將系統初始化數據加載到 MongoDB 和 ElasticSearch 中。

【離線推薦部分】
1. 通過 Azkaban 實現對於離線統計服務以離線推薦服務的調度,通過設定的運行時間完成對任務的觸發執行。
2. 離線統計服務從 MongoDB 中加載數據,將【電影平均評分統計】、【電影評分個數統計】、【最近電影評分個數統計】三個統計算法進行運行實現,並將計算結果回寫到 MongoDB 中;離線推薦服務從 MongoDB 中加載數據,通過 ALS 算法分別將【用
戶推薦結果矩陣】、【影片相似度矩陣】回寫到 MongoDB 中。

【實時推薦部分】
3. Flume 從綜合業務服務的運行日誌中讀取日誌更新,並將更新的日誌實時推送到Kafka 中; Kafka 在收到這些日誌之後,通過 kafkaStream 程序對獲取的日誌信息進行過濾處理,獲取用戶評分數據流【UID|MID|SCORE|TIMESTAMP】,併發送到另外一
個 Kafka 隊列; Spark Streaming 監聽 Kafka 隊列, 實時獲取 Kafka 過濾出來的用戶評分數據流, 融合存儲在 Redis 中的用戶最近評分隊列數據, 提交給實時推薦算法,完成對用戶新的推薦結果計算;計算完成之後,將新的推薦結構和 MongDB 數據庫
中的推薦結果進行合併。

【業務系統部分】
4. 推薦結果展示部分,從 MongoDB、 ElasticSearch 中將離線推薦結果、實時推薦結果、內容推薦結果進行混合,綜合給出相對應的數據。
5. 電影信息查詢服務通過對接 MongoDB 實現對電影信息的查詢操作。
6. 電影評分部分, 獲取用戶通過 UI 給出的評分動作,後臺服務進行數據庫記錄後,一方面將數據推動到 Redis 羣中,另一方面,通過預設的日誌框架輸出到 Tomcat 中的日誌中。
7. 項目通過 ElasticSearch 實現對電影的模糊檢索。
8. 電影標籤部分, 項目提供用戶對電影打標籤服務。

1.3 數據模型

1. Movie【電影數據表】

2. Rating【用戶評分表】

3. Tag【電影標籤表】

4. User【用戶表】

5. RateMoreMoviesRecently【最近電影評分個數統計表】

6. RateMoreMovies【電影評分個數統計表】

7. AverageMoviesScore【電影平均評分表】

8. MovieRecs【電影相似性矩陣】

9. UserRecs【用戶電影推薦矩陣】

10. StreamRecs【用戶實時電影推薦矩陣】

11. GenresTopMovies【電影類別 TOP10】

第 2 章 工具環境搭建

我們的項目中用到了多種工具進行數據的存儲、計算、採集和傳輸,本章主要簡單介紹設計的工具環境搭建。
如果機器的配置不足, 推薦只採用一臺虛擬機進行配置,而非完全分佈式,將該虛擬機 CPU 的內存設置的儘可能大,推薦爲 CPU > 4、 MEM > 4GB。
2.1 MongoDB(單節點)環境配置
2.2 Redis(單節點)環境配置
2.3 ElasticSearch(單節點)環境配置
2.4 Azkaban(單節點)環境配置
2.5 Spark(單節點)環境配置
2.6 Zookeeper(單節點)環境配置
2.7 Flume-ng(單節點)環境配置
2.8 Kafka(單節點)環境配置

第 3 章 創建項目構建

我們的項目主體用 Scala 編寫,採用 IDEA 作爲開發環境進行項目編寫,採用maven 作爲項目構建和管理工具。

第4 章 離線推薦服務建設

4.1 離線推薦服務

離線推薦服務是綜合用戶所有的歷史數據, 利用設定的離線統計算法和離線推薦算法週期性的進行結果統計與保存, 計算的結果在一定時間週期內是固定不變的,變更的頻率取決於算法調度的頻率。離線推薦服務主要計算一些可以預先進行統計和計算的指標, 爲實時計算和前端業務相應提供數據支撐。離線推薦服務主要分爲統計性算法、 基於 ALS 的協同過濾推薦算法以及基於ElasticSearch 的內容推薦算法。

4.2 離線統計服務

1 歷史熱門電影統計:根據所有歷史評分數據, 計算曆史評分次數最多的電影。
實現思路:通過 Spark SQL 讀取評分數據集,統計所有評分中評分數最多的電影,然後按照從大到小排序,將最終結果寫入 MongoDB 的 RateMoreMovies 數據集中。

 2 最近熱門電影統計:根據評分,按月爲單位計算最近時間的月份裏面評分數最多的電影集合。
實現思路:通過 Spark SQL 讀取評分數據集, 通過 UDF 函數將評分的數據時間修改爲月,然 後 統 計 每 月 電 影 的 評 分 數  統 計 完 成 之 後 將 數 據 寫 入 到 MongoDB 的RateMoreRecentlyMovies 數據集中。

3  電影平均得分統計:根據歷史數據中所有用戶對電影的評分,週期性的計算每個電影的平均得分。
實現思路:通過 Spark SQL 讀取保存在 MongDB 中的 Rating 數據集,通過執行以下 SQL 語句實現對於電影的平均分統計:

4 每個類別優質電影統計:根據提供的所有電影類別, 分別計算每種類型的電影集合中評分最高的 10 個電影。
實現思路:在計算完整個電影的平均得分之後,將影片集合與電影類型做笛卡爾積,然後過濾掉電影類型不符合的條目,將 DataFrame 輸出到 MongoDB 的 GenresTopMovies集合中。

4.3 基於隱語義模型的協同過濾推薦

項目採用 ALS 作爲協同過濾算法, 分別根據 MongoDB 中的用戶評分表和電影數據集計算用戶電影推薦矩陣以及電影相似度矩陣。

1 用戶電影推薦矩陣通過 ALS 訓練出來的 Model 來計算所有當前用戶電影的推薦矩陣,主要思路如下:
        1. UserId 和 MovieID 做笛卡爾積,產生( uid, mid)的元組
        2. 通過模型預測( uid, mid)的元組。
        3. 將預測結果通過預測分值進行排序。
        4. 返回分值最大的 K 個電影, 作爲當前用戶的推薦。
最後生成的數據結構如下:將數據保存到 MongoDB 的 UserRecs 表中

2 電影相似度矩陣通過 ALS 計算電影見相似度矩陣, 該矩陣用於查詢當前電影的相似電影併爲實時推薦系統服務。離線計算的 ALS 算法,算法最終會爲用戶、電影分別生成最終的特徵矩陣,分別是表示用戶特徵矩陣的 U(m x k)矩陣,每個用戶由 k 個特徵描述;表示物品特徵矩陣的 V(n x k)矩陣,每個物品也由 k 個特徵描述。V(n x k)表示物品特徵矩陣,每一行是一個 k 維向量,雖然我們並不知道每一個維度的特徵意義是什麼,但是 k 個維度的數學向量表示了該行對應電影的特徵。

數據集中任意兩個電影間相似度都可以由公式計算得到,電影與電影之間的相似度在一段時間內基本是固定值。最後生成的數據保存到 MongoDB 的 MovieRecs表中。

3 模型評估和參數選取
在上述模型訓練的過程中,我們直接給定了隱語義模型的 rank,iterations,lambda三個參數。對於我們的模型,這並不一定是最優的參數選取,所以我們需要對模型進行評估。通常的做法是計算均方根誤差( RMSE),考察預測評分與實際評分之間的誤差

第 5 章 實時推薦服務建設

5.1 實時推薦服務

實時計算與離線計算應用於推薦系統上最大的不同在於實時計算推薦結果應該反映最近一段時間用戶近期的偏好,而離線計算推薦結果則是根據用戶從第一次評分起的所有評分記錄來計算用戶總體的偏好。用戶對物品的偏好隨着時間的推移總是會改變的。比如一個用戶 u 在某時刻對電影 p 給予了極高的評分,那麼在近期一段時候, u 極有可能很喜歡與電影 p 類似的其他電影;而如果用戶 u 在某時刻對電影 q 給予了極低的評分,那麼在近期一段時候, u 極有可能不喜歡與電影 q 類似的其他電影。所以對於實時推薦,當用戶對一個電影進行了評價後,用戶會希望推薦結果基於最近這幾次評分進行一定的更新,使得推薦結果匹配用戶近期的偏好,滿足用戶近期的口味。如果實時推薦繼續採用離線推薦中的 ALS 算法,由於算法運行時間巨大,不具有實時得到新的推薦結果的能力;並且由於算法本身的使用的是評分表,用戶本次評分後只更新了總評分表中的一項,使得算法運行後的推薦結果與用戶本次評分之前的推薦結果基本沒有多少差別,從而給用戶一種推薦結果一直沒變化的感覺,很影響用戶體驗。另外,在實時推薦中由於時間性能上要滿足實時或者準實時的要求,所以算法的計算量不能太大,避免複雜、過多的計算造成用戶體驗的下降。鑑於此,推薦精度往往不會很高。實時推薦系統更關心推薦結果的動態變化能力,只要更新推薦結果的理由合理即可,至於推薦的精度要求則可以適當放寬。所以對於實時推薦算法,主要有兩點需求:
( 1)用戶本次評分後、或最近幾個評分後系統可以明顯的更新推薦結果;
( 2)計算量不大,滿足響應時間上的實時或者準實時要求;

5.2 實時推薦算法設計

當用戶 u 對電影 p 進行了評分,將觸發一次對 u 的推薦結果的更新。由於用戶 u 對電影 p 評分,對於用戶 u 來說,他與 p 最相似的電影們之間的推薦強度將發生變化,所以選取與電影 p 最相似的 K 個電影作爲候選電影。每個候選電影按照“推薦優先級”這一權重作爲衡量這個電影被推薦給用戶 u的優先級。這些電影將根據用戶 u 最近的若干評分計算出各自對用戶 u 的推薦優先級,然後與上次對用戶 u 的實時推薦結果的進行基於推薦優先級的合併、替換得到更新後的推薦結果。
具體來說:首先,獲取用戶 u 按時間順序最近的 K 個評分,記爲 RK;獲取電影 p 的最相似的 K 個電影集合,記爲 S;然後,對於每個電影 q S ,計算其推薦優先級 , 計算公式如下:

公式的意義如下:首先對於每個候選電影 q,從 u 最近的 K 個評分中,找出與 q 相似度較高>=0.6)的 u 已評分電影們,對於這些電影們中的每個電影 r,將 r 與 q 的相似度乘以用戶 u 對 r 的評分,將這些乘積計算平均數,作爲用戶 u 對電影 q 的評分預測

然後,將 u 最近的 K 個評分中與電影 q 相似的、且本身評分較高( >=3)的電影個數記爲 incount,計算 lgmax{incount,1}作爲電影 q 的“增強因子”,意義在於電影 q 與 u 的最近 K 個評分中的 n 個高評分(>=3)電影相似,則電影 q 的優先級被增加 lgmax{incount,1}。如果電影 q 與 u 的最近 K 個評分中相似的高評分電影越多,也就是說 n 越大,則電影 q 更應該被推薦,所以推薦優先級被增強的幅度較大;如果電影 q 與 u 的最近 K 個評分中相似的高評分電影越少,也就是n 越小,則推薦優先級被增強的幅度較小;而後,將 u 最近的 K 個評分中與電影 q 相似的、且本身評分較低( <3)的電影個數記爲 recount,計算 lgmax{recount,1}作爲電影 q 的“削弱因子”,意義在於電影 q 與 u 的最近 K 個評分中的 n 個低評分(<3)電影相似,則電影 q 的優先級被削減 lgmax{incount,1}。如果電影 q 與 u 的最近 K 個評分中相似的低評分電影越多,也就是說 n 越大,則電影 q 更不應該被推薦,所以推薦優先級被減弱的幅度較大;如果電影 q 與 u 的最近 K 個評分中相似的低評分電影越少,也就是 n 越小,則推薦優先級被減弱的幅度較小;最後,將增強因子增加到上述的預測評分中,並減去削弱因子,得到最終的 q 電影對於 u 的推薦優先級。在計算完每個候選電影 q 的 後,將生成一組<電影 q 的ID, q 的推薦優先級>的列表 updatedList:

5.3 實時推薦算法的實現

實時推薦算法的前提:1. 在 Redis 集羣中存儲了每一個用戶最近對電影的 K 次評分。實時算法可以快速獲取。
2. 離線推薦算法已經將電影相似度矩陣提前計算到了 MongoDB 中。
3. Kafka 已經獲取到了用戶實時的評分數據。
算法過程如下:實時推薦算法輸入爲一個評分<userId, movieId, rate, timestamp>,而執行的核心內容包括:獲取 userId 最近 K 次評分、獲取 movieId 最相似 K 個電影、計算候選電影的推薦優先級、更新對 userId 的實時推薦結果。
1 獲取用戶的 K 次最近評分:業務服務器在接收用戶評分的時候, 默認會將該評分情況以 userId, movieId, rate,timestamp 的格式插入到 Redis 中該用戶對應的隊列當中,在實時算法中,只需要通過 Redis 客戶端獲取相對應的隊列內容即可。
2 獲取當前電影最相似的 K 個電影:在 離線算 法中 , 已經預 先將電 影的 相似度矩 陣進行 了計 算 , 所以 每個電 影movieId 的最相似的 K 個電影很容易獲取: 從 MongoDB 中讀取 MovieRecs 數據,從 movieId 在 simHash 對應的子哈希表中獲取相似度前 K 大的那些電影。輸出是數 據 類 型 爲 Array[Int]的 數 組 , 表 示 與 movieId 最 相 似 的 電 影 集 合 , 並 命 名 爲candidateMovies 以作爲候選電影集合。
4 更新實時推薦結果:
當計算出候選電影的推薦優先級的數組 updatedRecommends<movieId, E>後,這個數組將被髮送到 Web 後臺服務器,與後臺服務器上 userId 的上次實時推薦結果recentRecommends<movieId, E>進行合併、替換並選出優先級 E 前 K 大的電影作爲本次新的實時推薦。具體而言:a.合併:將 updatedRecommends 與 recentRecommends 並集合成爲一個新的<movieId, E>數組;
b.替換(去重):當 updatedRecommends 與 recentRecommends 有重複的電影movieId 時, recentRecommends 中 movieId 的推薦優先級由於是上次實時推薦的結果,於是將作廢,替換成代表了更新後的 updatedRecommends 的 movieId 的推薦優級;
c.選取 TopK:在合併、替換後的<movieId, E>數組上,根據每個 movie 的推薦優先級,選擇出前 K 大的電影,作爲本次實時推薦的最終結果。

第 6 章 系統冷啓動問題

整個推薦系統更多的是依賴於用於的偏好信息進行電影的推薦, 那麼就會存在一個問題, 對於新註冊的用戶是沒有任何偏好信息記錄的, 那這個時候推薦就會出現問題, 導致沒有任何推薦的項目出現。處理這個問題一般是通過當用戶首次登陸時, 爲用戶提供交互式的窗口來獲取用戶對於物品的偏好。在本項目中, 當用戶第一次登陸的時候, 系統會詢問用戶對於影片類別的偏好。
當獲取用戶的偏好之後,對應於需要通過用戶偏好信息獲取的推薦結果,則更改爲通過對影片的類型的偏好的推薦。

第 7 章 基於內容的推薦服務

7.1 基於內容的推薦服務

原始數據中的 tag 文件,是用戶給電影打上的標籤,這部分內容想要直接轉成評分並不容易,不過我們可以將標籤內容進行提取, 得到電影的內容特徵向量,進而可以通過求取相似度矩陣。這部分可以與實時推薦系統直接對接,計算出與用戶當前評分電影的相似電影,實現基於內容的實時推薦。爲了避免熱門標籤對特徵提取的影響,我們還可以通過 TF-IDF 算法對標籤的權重進行調整,從而儘可能地接近用戶偏好。

然後通過電影特徵向量進而求出相似度矩陣,就可以爲實時推薦提供基礎,得到用戶推薦列表了。 可以看出,基於內容和基於隱語義模型,目的都是爲了提取出物品的特徵向量,從而可以計算出相似度矩陣。而我們的實時推薦系統算法正是基於相似度來定義的。

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