畢設(shè)實(shí)戰(zhàn):PySpark+Hadoop+ALS全流程解析)
每年畢設(shè)季的群消息里“推薦系統(tǒng)”一定是最熱鬧的關(guān)鍵詞之一。但說句得罪人的話十個(gè)標(biāo)榜“推薦系統(tǒng)畢設(shè)”的項(xiàng)目里有八個(gè)最后拿出來的是同一個(gè)東西一段Python腳本讀CSV、算個(gè)余弦相似度、Flask掛個(gè)查詢接口演示兩頁P(yáng)PT就結(jié)束了。老師一問“你的Hadoop在哪Spark做了什么”基本就沉默到底。我見過太多人卡在同一個(gè)位置題目叫“基于PythonPySparkHadoop的圖書推薦系統(tǒng)”聽起來很完整但真正動(dòng)手時(shí)才發(fā)現(xiàn)環(huán)境裝了三天、算法跑不得數(shù)據(jù)大屏不知道從哪下手。這篇就來拆解一下一個(gè)能拿得出手、能通過答辯的圖書推薦系統(tǒng)到底應(yīng)該怎么做。從選題邏輯、整體架構(gòu)、環(huán)境搭建、算法實(shí)現(xiàn)到可視化大屏和答辯準(zhǔn)備一條線拉完。特別適合選了這個(gè)題但還沒想清楚怎么落地的同學(xué)以及想用“大數(shù)據(jù)推薦可視化”組合來撐起畢設(shè)工作量的同學(xué)。1. 為什么圖書推薦系統(tǒng)是“性價(jià)比”最高的畢設(shè)選題——選題邏輯1.1 圖書數(shù)據(jù)為什么適合做推薦系統(tǒng)先想清楚一個(gè)問題同樣是經(jīng)典選題為什么是圖書而不是電影、新聞、商品核心原因是數(shù)據(jù)特性。電影推薦有個(gè)麻煩事——一部電影的評分受上映時(shí)間、宣傳力度、輿論熱點(diǎn)影響極大《流浪地球2》和《滿江紅》這種檔期電影在評分榜上天然占便宜新聞推薦更是重災(zāi)區(qū)時(shí)效性一天一變推薦系統(tǒng)做得再好新聞第二天就過期了。但圖書完全不一樣一本書的生命周期以年甚至十年為單位《三體》火了十年依然有大量讀者在評、在讀。這種長尾特征讓用戶行為數(shù)據(jù)積累得更有價(jià)值也更適合協(xié)同過濾算法發(fā)揮。還有一個(gè)細(xì)節(jié)容易被忽略圖書的“語義屬性”非常干凈。每本書有固定的作者、分類、出版社、標(biāo)題關(guān)鍵詞這些結(jié)構(gòu)化信息可以直接用于內(nèi)容推薦和冷啟動(dòng)方案設(shè)計(jì)。你拿到的圖書數(shù)據(jù)集每一條記錄都是干凈的“用戶ID、圖書ID、評分、時(shí)間戳”不需要做大量的文本清洗。1.2 技術(shù)棧怎么撐起工作量又不至于失控畢設(shè)評審?fù)ǔ?慈鹿ぷ髁繅虿粔?、技術(shù)有沒有難度、系統(tǒng)完不完整。純Python寫推薦算法確實(shí)不夠看但如果你一上來就搞Flink實(shí)時(shí)流、架構(gòu)上搞微服務(wù)那是不給自己留活路三個(gè)月也畢不了業(yè)。“Hadoop存數(shù)據(jù) PySpark算數(shù)據(jù) MySQL存結(jié)果 Flask搭接口 ECharts做大屏”這個(gè)組合是經(jīng)過大量畢設(shè)驗(yàn)證的黃金搭配。Hadoop承擔(dān)海量原始數(shù)據(jù)的分布式存儲Spark完成離線批處理與模型訓(xùn)練大屏把推薦效果和統(tǒng)計(jì)數(shù)據(jù)呈現(xiàn)出來。既有分布式大數(shù)據(jù)處理的“殼”又有協(xié)同過濾算法的“核”還有前端可視化的“面子”每個(gè)環(huán)節(jié)拿出來都能在論文里獨(dú)立寫一章。1.3 數(shù)據(jù)集從哪來很多人在這一步就被卡死了。我的建議是先別自己寫爬蟲用現(xiàn)成的開源數(shù)據(jù)集。一些公開的數(shù)據(jù)競賽平臺放出過整理好的圖書推薦語料典型結(jié)構(gòu)就是兩張表一張用戶評分表user_id、book_id、rating、timestamp一張圖書信息表book_id、title、author、category。拿到這種數(shù)據(jù)你省下的時(shí)間足夠把算法和鏈路打磨好。如果實(shí)在找不到完全匹配的也有備用方案把公開的MovieLens數(shù)據(jù)集映射成圖書數(shù)據(jù)或者自己按照業(yè)務(wù)邏輯寫一個(gè)小型造數(shù)腳本模擬出用戶行為分布。這里順帶提醒一下自己造數(shù)據(jù)不要拍腦袋要讓“少量用戶打高分、大量用戶低活躍、長尾圖書被冷落”這種真實(shí)分布出現(xiàn)否則后面算法評估環(huán)節(jié)會(huì)很尷尬。2. 一圖看懂全鏈路Hadoop、Spark、MySQL、可視化大屏各司其職2.1 存儲層與計(jì)算層的分工很多學(xué)生搭完環(huán)境卻搞不清楚每個(gè)組件到底在干嘛答辯被問就懵。先把分工說透HDFS承擔(dān)的是原始數(shù)據(jù)倉庫的角色。用戶評分原始CSV、圖書元數(shù)據(jù)這些都放到HDFS上。為什么用HDFS而不是直接放本地磁盤因?yàn)槟愕恼撐暮图夹g(shù)報(bào)告里需要解釋“大數(shù)據(jù)存儲方案”——當(dāng)數(shù)據(jù)量從幾百兆漲到幾百G、幾T時(shí)本地磁盤的單點(diǎn)瓶頸就暴露了HDFS通過分塊存儲和副本機(jī)制解決了這個(gè)問題。在畢設(shè)答辯中這個(gè)理由足夠站得住。Spark負(fù)責(zé)離線計(jì)算引擎。數(shù)據(jù)清洗過濾無效評分、去重、統(tǒng)計(jì)指標(biāo)圖書熱度、用戶活躍度、評分分布、ALS模型訓(xùn)練與推薦結(jié)果生成全部由PySpark作業(yè)完成。Spark之所以比傳統(tǒng)Python腳本有優(yōu)勢一句話就能說清當(dāng)處理的數(shù)據(jù)量超出單機(jī)內(nèi)存時(shí)Spark可以通過RDD和DataFrame的分區(qū)機(jī)制做分布式計(jì)算。MySQL則扮演結(jié)果服務(wù)層。Spark算出來的TopN推薦列表、圖書分類統(tǒng)計(jì)、評分分布指標(biāo)、推薦命中率指標(biāo)統(tǒng)一寫入MySQL。為什么結(jié)果要落MySQL因?yàn)榇笃两涌诤推胀ú樵兌夹枰鞍礂l件快速查找”HDFS是全量批次讀做不了交互式SQL查詢MySQL才適合這種場景。2.2 數(shù)據(jù)流轉(zhuǎn)鏈路整個(gè)系統(tǒng)的數(shù)據(jù)流是單方向的清晰好講原始CSV數(shù)據(jù) → 上傳到HDFS → PySpark讀取并清洗 → 暫存為Parquet中間表 → ALS模型訓(xùn)練與推薦 → 推薦結(jié)果寫MySQL → Flask提供REST接口 → ECharts大屏渲染這里有一個(gè)很實(shí)用的小細(xì)節(jié)清洗后的中間結(jié)果先保存為Parquet再在訓(xùn)練階段讀取而不是每次從頭讀CSV再清一遍。Parquet是列式存儲格式帶Schema信息壓縮率也高Spark讀起來比CSV快數(shù)倍。真跑到幾十萬條評分?jǐn)?shù)據(jù)時(shí)這個(gè)差異你是能感受到的。2.3 為什么推薦結(jié)果不直接放HDFS這個(gè)問題幾乎是答辯必問把它想清楚你整個(gè)架構(gòu)就立住了。HDFS擅長順序讀大文件比如“全量掃描數(shù)據(jù)”這種操作。但推薦結(jié)果的使用場景是前端大屏請求“給我按類別統(tǒng)計(jì)”或者“展示評分最高的10本書”這就是小范圍的精確查詢。如果讓前端直接查HDFSJVM開銷、RPC延遲、NameNode元數(shù)據(jù)壓力都會(huì)成為一個(gè)笑話。從專業(yè)角度說HDFS承擔(dān)離線全量計(jì)算關(guān)系型數(shù)據(jù)庫承擔(dān)在線服務(wù)這是經(jīng)典的大數(shù)據(jù)Lambda架構(gòu)的離線分支思想論文里這么一寫深度就出來了。3. 環(huán)境搭建是最容易翻車的環(huán)節(jié)偽分布式踩坑實(shí)錄3.1 環(huán)境選型虛擬機(jī)Linux比Windows省一半時(shí)間先給出一個(gè)我反復(fù)驗(yàn)證過的推薦組合VMware虛擬機(jī) Ubuntu 20.04 Server版 JDK 8 Hadoop 3.3.x Spark 3.3.x對應(yīng)hadoop3版本 Python 3.8 PySpark 3.3.x。很多人一上來就在Windows上直接裸裝Hadoop然后陷入winutils.exe、hadoop.dll、Cygwin的各種兼容性地獄一搞就是一個(gè)星期。我的經(jīng)驗(yàn)是如果你不是想在Windows內(nèi)核層面折騰就別走這條路。虛擬機(jī)里裝個(gè)Ubuntu Server命令行操作體驗(yàn)更接近真實(shí)大數(shù)據(jù)集群后續(xù)寫論文時(shí)截圖也更“專業(yè)”。給虛擬機(jī)的內(nèi)存建議是4G以上硬盤40G起步Hadoop的NameNode和DataNode進(jìn)程加上Spark的Driver和Executor內(nèi)存小了分分鐘OOM。3.2 Hadoop偽分布式搭建的三步與一個(gè)必坑偽分布式就是“單機(jī)模擬集群”對畢設(shè)完全夠用。流程三步第一步基礎(chǔ)配置。確保JAVA_HOME路徑寫進(jìn)/etc/environment或~/.bashrcHadoop解壓到/opt/hadoop并把bin、sbin加入PATH。注意Hadoop3要求JDK8以上別用JDK17有些版本跑起來會(huì)報(bào)模塊訪問錯(cuò)誤。第二步改核心配置。在core-site.xml里設(shè)置NameNode地址configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namedfs.permissions.enabled/name valuefalse/value /property /configuration在hdfs-site.xml里設(shè)置副本數(shù)偽分布式模式下副本一定要設(shè)成1property namedfs.replication/name value1/value /property第三步初始化與啟動(dòng)配置SSH免密登錄ssh-keygen -t rsa生成密鑰后把公鑰加到authorized_keys然后只格式化一次NameNodehdfs namenode -format start-dfs.sh jpsjps是你最忠實(shí)的朋友看到NameNode、DataNode、SecondaryNameNode三個(gè)進(jìn)程就算成功。這里最大的坑就是重復(fù)格式化NameNode。只要改了一次hdfs配置很多人習(xí)慣性再格式化一次結(jié)果DataNode和NameNode的clusterID對不上啟動(dòng)后DataNode一直報(bào)錯(cuò)退出。正確做法是格式化前把/opt/hadoop/tmp或者你自己指定的dfs.namenode.name.dir目錄刪干凈再格式化然后起來。踩過這個(gè)坑的人現(xiàn)在應(yīng)該都在點(diǎn)頭。3.3 PySpark連接HDFS的版本與權(quán)限問題PySpark連HDFS最煩的就是版本不匹配。下載Spark時(shí)選那個(gè)“hadoop3”的預(yù)編譯包別拿一個(gè)Spark 2.x和Hadoop 3.x硬配。版本不對的時(shí)候報(bào)錯(cuò)千奇百怪最典型的是NoSuchMethodError或者ClassNotFound這些一眼看上去根本不知道是哪出了問題。連接配置在SparkSession里搞定spark SparkSession.builder \ .appName(BookRec) \ .master(local[*]) \ .config(spark.hadoop.fs.defaultFS, hdfs://localhost:9000) \ .config(spark.serializer, org.apache.spark.serializer.KryoSerializer) \ .getOrCreate()注意spark.serializer這一行很多教程不寫實(shí)際跑起來遇到復(fù)雜對象序列化會(huì)踩坑。前面我在core-site.xml里加了dfs.permissions.enabledfalse這是偽分布式學(xué)習(xí)環(huán)境的推薦做法否則你用Python客戶端往HDFS寫文件大概率遇到Permission denied排查一輪權(quán)限組還要額外耗半小時(shí)。3.4 內(nèi)存不足與端口沖突的快速診斷偽分布式最常見的問題是跑訓(xùn)練時(shí)Executor直接崩掉。建議在spark-defaults.conf里限制內(nèi)存spark.driver.memory 1g spark.executor.memory 1g spark.executor.cores 1這個(gè)配置在畢設(shè)數(shù)據(jù)量下完全夠用而且能防止你從虛擬機(jī)的2G內(nèi)存里硬擠。端口沖突也經(jīng)常出現(xiàn)hdfs://localhost:9000被占、50070HDFS Web UI被占。排查命令就是netstat -tlnp | grep 9000找到占用進(jìn)程后要么殺掉要么改端口。這些內(nèi)容寫進(jìn)論文的“系統(tǒng)調(diào)試與問題分析”章節(jié)都是真實(shí)工作量。4. 推薦算法落地ALS協(xié)同過濾與冷啟動(dòng)處理的完整實(shí)現(xiàn)4.1 ALS原理一句話版本與公式直覺ALS交替最小二乘是Spark MLlib內(nèi)置的協(xié)同過濾算法屬于矩陣分解類。核心思想是把用戶對圖書的評分矩陣R用戶×圖書近似分解成兩個(gè)低維矩陣U用戶×隱因子和V圖書×隱因子的乘積讓UV的結(jié)果盡可能接近真實(shí)評分?!敖惶妗钡囊馑际窍裙潭╒把U當(dāng)未知數(shù)求解最小二乘問題再固定U求解V。如此交替迭代直到收斂。每次只解一個(gè)矩陣復(fù)雜度大幅下降又能分布式并行所以Spark里實(shí)現(xiàn)得特別好。它的優(yōu)勢一句話就能說清能處理極度稀疏的評分矩陣。圖書總量可能幾萬本但一個(gè)用戶評過書的可能只有幾十本ALS通過隱因子向量去捕捉“用戶偏好模式”和“圖書屬性模式”比單純的物品相似度計(jì)算在稀疏數(shù)據(jù)上更漂亮。4.2 基于PySpark的ALS完整實(shí)現(xiàn)假設(shè)清洗后的數(shù)據(jù)格式是user_id,book_id,rating,timestamp u1001,b2001,5,1635000000 u1001,b2005,4,1635003600 u1002,b2001,3,1635004200完整的訓(xùn)練與推薦代碼如下from pyspark.sql import SparkSession from pyspark.ml.recommendation import ALS from pyspark.ml.feature import StringIndexer from pyspark.ml.evaluation import RegressionEvaluator spark SparkSession.builder \ .appName(BookRecALS) \ .master(local[*]) \ .config(spark.hadoop.fs.defaultFS, hdfs://localhost:9000) \ .getOrCreate() # 讀取原始數(shù)據(jù)注意數(shù)據(jù)在HDFS上 df spark.read.csv(hdfs://localhost:9000/data/ratings.csv, headerTrue, inferSchemaTrue) # ALS要求ID是數(shù)值型字符串ID要轉(zhuǎn)索引 user_idx StringIndexer(inputColuser_id, outputColuser_idx).fit(df) book_idx StringIndexer(inputColbook_id, outputColbook_idx).fit(df) df_indexed book_idx.transform(user_idx.transform(df)) # 劃分訓(xùn)練集和測試集 train, test df_indexed.randomSplit([0.8, 0.2], seed42) # 訓(xùn)練ALS模型 als ALS( userColuser_idx, itemColbook_idx, ratingColrating, rank10, # 隱因子數(shù)量 maxIter10, # 最大迭代次數(shù) regParam0.1, # 正則化系數(shù) coldStartStrategydrop ) model als.fit(train) # 評估計(jì)算RMSE evaluator RegressionEvaluator( metricNamermse, labelColrating, predictionColprediction ) rmse evaluator.evaluate(model.transform(test)) print(fRMSE: {rmse})模型訓(xùn)練完成后生成推薦結(jié)果# 為每個(gè)用戶推薦5本圖書 user_recs model.recommendForAllUsers(5) # 轉(zhuǎn)換為可讀的推薦列表 recs_flat user_recs.select( user_idx, explode(recommendations).alias(rec) ).select( user_idx, col(rec.book_idx).alias(book_idx), col(rec.rating).alias(pred_rating) ) # 把索引映射回原始ID user_id_mapping user_idx.fit(df).labels book_id_mapping book_idx.fit(df).labels # 這里通過join把索引還原成原始user_id和book_id recs_final recs_flat.join(user_map, user_idx).join(book_map, book_idx)這里要提醒一個(gè)容易漏的點(diǎn)訓(xùn)練前一定要把字符串用戶ID和圖書ID轉(zhuǎn)成數(shù)值索引ALS不接受字符串。4.3 冷啟動(dòng)處理熱門兜底與內(nèi)容召回冷啟動(dòng)是推薦系統(tǒng)的經(jīng)典問題也是答辯考官最喜歡追問的地方。新用戶沒有歷史行為協(xié)同過濾完全失效。我的處理方法是分層策略第一層熱門圖書兜底。對沒有行為記錄的用戶直接推薦全局評分人數(shù)最多、平均分最高的圖書。這個(gè)邏輯簡單有效而且大屏上正好也要展示熱門圖書Top10一套統(tǒng)計(jì)結(jié)果兩處復(fù)用。第二層基于內(nèi)容屬性的召回。利用圖書信息表里的分類和作者字段構(gòu)造“同作者其他作品”“同分類熱門書”這種內(nèi)容推薦策略。代碼實(shí)現(xiàn)也不復(fù)雜從洗好的圖書表里按分類聚合取同類中評分最高的若干本作為候選池。這兩層加在一起論文里就可以寫“系統(tǒng)采用協(xié)同過濾為主、基于內(nèi)容的策略解決冷啟動(dòng)問題的混合推薦方案”這個(gè)表述在答辯時(shí)非常加分。4.4 推薦效果怎么評估才能讓評委信服不要只丟一個(gè)RMSE就完事。RMSE反映的是“評分預(yù)測準(zhǔn)確度”但推薦系統(tǒng)實(shí)際用的是TopN展示所以還要算“TopN命中率”在測試集中用戶真實(shí)評分過且評分≥4的圖書有多少出現(xiàn)在推薦列表前10里。這個(gè)指標(biāo)更貼近業(yè)務(wù)也更好向非算法背景的評委解釋。可以做一個(gè)樸素對比隨機(jī)推薦Top10的命中率 vs ALS推薦Top10的命中率。幾乎所有數(shù)據(jù)集上ALS都會(huì)明顯勝出。在論文里放一張這樣的對比表推薦效果的說服力直接拉滿。5. 可視化大屏的數(shù)據(jù)管道從Spark結(jié)果到ECharts圖表5.1 大屏面板設(shè)計(jì)展示什么由答辯邏輯決定大屏不是裝飾品它是你向評委“講數(shù)據(jù)故事”的舞臺。不要放一堆花哨無意義的圖表要圍繞“圖書推薦系統(tǒng)到底有多能打”來設(shè)計(jì)面板。我做的方案是六塊面板圖表類型說明核心指標(biāo)卡數(shù)字卡片用戶總數(shù)、圖書總數(shù)、評分總數(shù)、推薦覆蓋率圖書分類分布環(huán)形圖各分類圖書占比展示數(shù)據(jù)構(gòu)成熱門圖書Top10橫向柱狀圖評分人數(shù)最多的書直觀展示數(shù)據(jù)熱度評分分布柱狀圖1-5分的人數(shù)分布驗(yàn)證評分?jǐn)?shù)據(jù)質(zhì)量每日評分趨勢折線圖按時(shí)間聚合評分量體現(xiàn)“數(shù)據(jù)在流動(dòng)”用戶推薦列表表格輸入用戶ID展示其Top5推薦結(jié)果連動(dòng)交互注意最后這塊表格答辯現(xiàn)場給評委演示“輸入一個(gè)用戶ID立刻看到系統(tǒng)給他推了什么書及推薦理由”這是大屏的互動(dòng)亮點(diǎn)也是系統(tǒng)“推薦”能力的直接證據(jù)。5.2 PySpark寫MySQL——最后一個(gè)坑Spark算完結(jié)果要寫入MySQL這里需要使用JDBC驅(qū)動(dòng)。代碼主邏輯recs_final.write \ .format(jdbc) \ .option(url, jdbc:mysql://localhost:3306/book_rec?useSSLfalsecharacterEncodingutf8serverTimezoneAsia/Shanghai) \ .option(dbtable, recommend_result) \ .option(user, root) \ .option(password, yourpassword) \ .option(driver, com.mysql.cj.jdbc.Driver) \ .mode(overwrite) \ .save()這里有兩個(gè)坑我必須提一是MySQL連接串里的characterEncodingutf8不能少否則中文書名全變問號二是serverTimezoneAsia/Shanghai不能少否則報(bào)時(shí)區(qū)異常。另外運(yùn)行時(shí)缺驅(qū)動(dòng)會(huì)報(bào)ClassNotFoundException需要把mysql-connector-java.jar放到Spark的jars目錄下或者用--jars參數(shù)提交。這些細(xì)節(jié)寫進(jìn)論文的“系統(tǒng)實(shí)現(xiàn)”里就是實(shí)打?qū)嵉呐佩e(cuò)經(jīng)驗(yàn)。5.3 Flask接口與ECharts前端大屏后端不用搞得太重Flask就夠。提供幾個(gè)只讀接口from flask import Flask, jsonify import pymysql app Flask(__name__) def get_conn(): return pymysql.connect( hostlocalhost, userroot, passwordyourpassword, databasebook_rec, charsetutf8mb4, cursorclasspymysql.cursors.DictCursor ) app.route(/api/summary) def summary(): conn get_conn() with conn.cursor() as cur: cur.execute(SELECT COUNT(DISTINCT user_id) AS users FROM actions) users cur.fetchone()[users] # 類似地查圖書數(shù)、評分?jǐn)?shù)... conn.close() return jsonify({users: users, books: books, ratings: ratings}) app.route(/api/hot_books) def hot_books(): # 查出熱門圖書Top10返回JSON pass app.route(/api/recommend/user_id) def recommend(user_id): # 查出該用戶Top5推薦結(jié)果 pass前端用ECharts渲染大屏通用的“深色底亮色圖表”方案卡片式布局。小技巧用flex布局加百分比寬度能讓大屏在不同分辨率下不錯(cuò)位圖表配色統(tǒng)一用一套色板比如深藍(lán)底亮黃高亮比五顏六色更有質(zhì)感。ECharts的setOption可以直接接收Flask返回的JSON數(shù)據(jù)鏈路非常短。如果擔(dān)心答辯現(xiàn)場網(wǎng)絡(luò)抽風(fēng)把大屏做成“啟動(dòng)時(shí)加載一次 手動(dòng)刷新按鈕”的模式比追求實(shí)時(shí)輪詢更穩(wěn)妥演示效果也更可控。5.4 大屏常見問題排查中文亂碼、時(shí)區(qū)報(bào)錯(cuò)上面已經(jīng)提了。還有一個(gè)容易忽略的是ECharts柱狀圖的書名太長會(huì)擠壓布局用label: { formatter: ... }配合ellipsis截?cái)?。大屏截圖要放進(jìn)論文所以分辨率至少要1920×1080截圖前把瀏覽器縮放調(diào)好不要截出模糊的小圖。6. 論文、PPT與答辯讓評委看到的不只是“能跑”6.1 論文五張必放圖論文文檔常說的LW文檔是畢業(yè)設(shè)計(jì)的另一半工作量。很多學(xué)生代碼跑通了論文寫成流水賬答辯時(shí)一樣被挑。核心原則是一張圖頂三百字五張圖必須有系統(tǒng)總體架構(gòu)圖畫清楚Hadoop、Spark、MySQL、Flask、ECharts的分層關(guān)系。數(shù)據(jù)流圖展示原始數(shù)據(jù)從進(jìn)入HDFS到最終大屏展示的完整鏈路。數(shù)據(jù)庫表結(jié)構(gòu)圖用戶表、圖書表、評分表、推薦結(jié)果表的字段和關(guān)聯(lián)關(guān)系。算法流程圖ALS的訓(xùn)練、預(yù)測、推薦生成流程配合文字公式。大屏效果截圖必須是真機(jī)運(yùn)行截圖標(biāo)注各區(qū)域?qū)?yīng)的功能模塊。其中算法流程圖可以用Visio或draw.io畫別用截圖代替手畫圖一定要自己畫。6.2 PPT結(jié)構(gòu)與演示節(jié)奏PPT不需要長11頁以內(nèi)最佳。我習(xí)慣的結(jié)構(gòu)項(xiàng)目背景與意義1頁國內(nèi)外研究現(xiàn)狀1頁快速帶過相關(guān)技術(shù)棧1頁Hadoop、Spark、ALS、ECharts系統(tǒng)架構(gòu)圖1頁推薦算法原理2頁著重講ALS和冷啟動(dòng)系統(tǒng)核心實(shí)現(xiàn)2頁代碼大屏測試與評估1頁RMSE命中率對比表總結(jié)與展望1頁重點(diǎn)在“系統(tǒng)核心實(shí)現(xiàn)”和“測試評估”因?yàn)檫@是你真正做完的部分。演示的時(shí)候帶兩套預(yù)案一是提前錄好一段2分鐘的操作演示視頻防止現(xiàn)場環(huán)境崩掉二是現(xiàn)場直接開大屏實(shí)時(shí)演示。雙保險(xiǎn)。6.3 高頻答辯問題梳理附話術(shù)這是整篇博文最“值錢”的部分問來問去就那么幾個(gè)問題提前準(zhǔn)備好就能過關(guān)評委常問應(yīng)答要點(diǎn)ALS的原理是什么把評分矩陣分解為兩個(gè)低維矩陣的乘積交替固定一邊求解另一邊迭代最小化誤差為什么用HDFS存儲不用MySQLHDFS適合海量數(shù)據(jù)分布式存儲和全量批讀MySQL承擔(dān)在線查詢服務(wù)兩類引擎各司其職數(shù)據(jù)量大了怎么擴(kuò)展Spark層的分區(qū)數(shù)可以調(diào)大Hadoop可以通過增加DataNode節(jié)點(diǎn)橫向擴(kuò)容ALS本身支持分布式迭代推薦效果怎么證明訓(xùn)練/測試集劃分計(jì)算RMSE還要算TopN命中率與隨機(jī)推薦對比新用戶沒有行為數(shù)據(jù)怎么辦熱門圖書榜兜底 基于圖書分類/作者的內(nèi)容召回屬于混合推薦方案你的數(shù)據(jù)從哪來公開的圖書推薦數(shù)據(jù)集公開來源有評分時(shí)間戳適合算法訓(xùn)練這些回答都指向同一個(gè)邏輯你做的不是一個(gè)“玩具”而是一個(gè)在數(shù)據(jù)規(guī)模增長時(shí)仍然有演進(jìn)路徑的系統(tǒng)。把這個(gè)邏輯貫穿到論文、PPT、答辯中整篇畢設(shè)的內(nèi)部一致性就有了。做這類大數(shù)據(jù)畢設(shè)我最大的體會(huì)是環(huán)境只是舞臺算法和架構(gòu)才是主角。很多同學(xué)花三周時(shí)間搭環(huán)境最后一周草草寫代碼答辯時(shí)老師問兩句就露餡。正確的精力分配應(yīng)該是環(huán)境兩周內(nèi)跑通把省下的時(shí)間砸在算法調(diào)優(yōu)、大屏打磨、論文圖表上——這三樣才是真正決定成績的東西。最后分享一個(gè)實(shí)戰(zhàn)小技巧答辯前把“演示腳本”寫在一頁紙上每一步操作對應(yīng)論文里的哪張圖、哪個(gè)章節(jié)標(biāo)清楚。評委問“這個(gè)圖表對應(yīng)你論文哪里”的時(shí)候你脫口而出“論文5.3節(jié)、圖5-7”這種流暢感比任何花哨的技術(shù)點(diǎn)都加分。畢竟答辯的本質(zhì)不是“證明你全對”而是“證明你清楚地知道自己在做什么”。