免费国产精品自在自线-91精品国产色综合久久久浪潮-99热久久免费频精品-国产精品国模在线观看-久久亚洲国产精品成人?V秋霞-久久国产一级A片免费播放-亚洲国产欧洲综合97久久-久久国产白嫩美女呻吟高潮

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實戰(zhàn)洞察。

基于協(xié)同過濾的Java電影推薦系統(tǒng)源碼實戰(zhàn)

基于協(xié)同過濾的Java電影推薦系統(tǒng)源碼實戰(zhàn) 簡介基于協(xié)同過濾算法的Java電影推薦系統(tǒng)源碼面向Java開發(fā)者、電影類流媒體平臺及相關(guān)專業(yè)學(xué)習(xí)者。系統(tǒng)通過分析用戶歷史行為數(shù)據(jù)提取偏好特征并智能推薦符合口味的電影適合課程設(shè)計、畢業(yè)設(shè)計參考或二次開發(fā)起點。壓縮包共76個文件包括38個Java源文件、15個JSP頁面、10個XML配置、2個SQL腳本及JS、CSS等業(yè)務(wù)邏輯、頁面展示與數(shù)據(jù)庫腳本分層存放整體結(jié)構(gòu)清晰壓縮包大小僅1.1MB下載部署輕量。目前已有823人學(xué)習(xí)/下載受到開發(fā)者關(guān)注。源碼可直接導(dǎo)入常見IDE運(yùn)行配合SQL腳本快速初始化數(shù)據(jù)庫幫助理解協(xié)同過濾算法從評分矩陣構(gòu)建、相似度計算到TopN推薦的完整落地過程同時可借鑒JSPServlet風(fēng)格的Web分層設(shè)計、數(shù)據(jù)訪問與接口組織方式是JavaWeb與推薦系統(tǒng)入門及項目實戰(zhàn)的高性價比參考。1. 基于協(xié)同過濾算法的Java電影推薦系統(tǒng)源碼它解決什么問題值不值得照著做你手頭有一個電影站的后臺每天進(jìn)來幾千用戶留下幾萬條點擊和打分但首頁只能按時間或熱度排運(yùn)營問你“能不能給每個人推不一樣的電影”。這個標(biāo)題給的就是一條能直接落地的路線基于協(xié)同過濾算法的Java電影推薦系統(tǒng)源碼從數(shù)據(jù)表設(shè)計、相似度計算到Top-N推薦接口全部用Java技術(shù)棧實現(xiàn)不依賴Python服務(wù)、不引入Spark一臺普通服務(wù)器加MySQL就能跑起來。它適合三類人做Java課程設(shè)計和畢業(yè)設(shè)計的學(xué)生接私活需要快速交付推薦模塊的工程師以及正在刷java基礎(chǔ)面經(jīng)、隨時可能被問到“協(xié)同過濾怎么算、缺點是什么”的求職者。后面我會拆成算法選型、數(shù)據(jù)建模、核心代碼、工程接口和踩坑記錄五塊每一步都能照著抄也能照著排錯。2. 協(xié)同過濾算法選型UserCF與ItemCF的取舍以及Java實現(xiàn)前的數(shù)據(jù)準(zhǔn)備協(xié)同過濾不是一種算法而是一族算法落地前如果選錯方向后面寫多少代碼都救不回來。這一章先解決兩個問題你的場景到底選UserCF還是ItemCF以及算法跑起來之前評分?jǐn)?shù)據(jù)應(yīng)該以什么形態(tài)裝進(jìn)Java內(nèi)存。2.1 UserCF還是ItemCF先看你的用戶量和電影量協(xié)同過濾分兩派基于用戶的UserCF和基于物品的ItemCF。UserCF先找出和你口味最接近的一批用戶再把這批用戶看過而你沒看過的電影推薦給你ItemCF反過來先算出電影和電影的相似度然后從你自己打過高分的電影出發(fā)找沒看過的相似片單。兩者數(shù)學(xué)上都在算相似度矩陣但適用場景差的非常多。我的經(jīng)驗是用戶量遠(yuǎn)大于物品量的場景UserCF會先崩。比如一個電影站有50萬注冊用戶、1萬部電影UserCF要算50萬乘以50萬的用戶相似度矩陣那就不叫推薦系統(tǒng)叫內(nèi)存殺手。反過來物品量遠(yuǎn)大于用戶量的場景ItemCF的物品相似度表同樣會爆炸。電影推薦的典型特征是物品穩(wěn)定、用戶量大業(yè)內(nèi)普遍首選ItemCF做主力UserCF用來做“和你口味相似的人也在看”這種社交化榜單兩個一起上也沒問題。在這套源碼里我會把兩個都實現(xiàn)通過配置文件切換默認(rèn)走ItemCF。這樣既方便交作業(yè)時講清選型理由也方便你拿同一份數(shù)據(jù)做對比實驗。還有兩個必調(diào)的參數(shù)相似度閾值和鄰居數(shù)K。我一般把“相似度低于0.1的鄰居直接扔掉”做成常量配置而不是散落在代碼里后面調(diào)參時只需要改配置文件不用重編譯。2.2 MovieLens數(shù)據(jù)集與Java實體建模從CSV到User-Rating矩陣推薦系統(tǒng)沒有數(shù)據(jù)就是空中樓閣最常見的做法是拿MovieLens開源數(shù)據(jù)集里面包含users、movies、ratings三個文件。ratings文件每行是“userId::movieId::rating::timestamp”評分是1到5的整數(shù)這個字段格式直接決定了Java代碼里怎么切分字符串。把這份數(shù)據(jù)映射成Java對象最少只需要兩個東西一個Rating實體類和一個能裝載整個評分矩陣的DataLoader。下面這段代碼先定義了Rating實體再用一個方法把CSV解析成嵌套Map。為什么用Map而不是二維數(shù)組假設(shè)1萬個用戶、1萬部電影稠密二維數(shù)組要開1億個格子double[][]占用約800MB內(nèi)存而真實評分記錄可能只有10萬條。稀疏Map只存放有的位置內(nèi)存占用能降一個數(shù)量級。public class Rating { private int userId; private int movieId; private double score; private long timestamp; public Rating(int userId, int movieId, double score, long timestamp) { this.userId userId; this.movieId movieId; this.score score; this.timestamp timestamp; } public int getUserId() { return userId; } public int getMovieId() { return movieId; } public double getScore() { return score; } public long getTimestamp() { return timestamp; } }public class DataLoader { public static MapInteger, MapInteger, Double loadRatings(String path) throws IOException { MapInteger, MapInteger, Double userItemMap new HashMap(); try (BufferedReader br new BufferedReader(new FileReader(path))) { String line; while ((line br.readLine()) ! null) { String[] fields; if (line.contains(::)) { fields line.split(::); } else { fields line.split(,); } if (fields.length 3) { continue; } try { int userId Integer.parseInt(fields[0]); int movieId Integer.parseInt(fields[1]); double score Double.parseDouble(fields[2]); userItemMap.computeIfAbsent(userId, k - new HashMap()).put(movieId, score); } catch (NumberFormatException e) { // 臟數(shù)據(jù)直接跳過真實環(huán)境不能因為一行壞數(shù)據(jù)掛掉整個加載過程 } } } return userItemMap; } }邏輯說明userItemMap的結(jié)構(gòu)是“用戶ID - (電影ID - 評分)”這是UserCF的輸入形態(tài)。關(guān)鍵方法是computeIfAbsent它是java基礎(chǔ)里很常用的Map操作等價于“key不存在就new一個HashMap放進(jìn)去存在就直接用”比先判斷再put的三行樣板代碼干凈得多。注意我在解析里同時兼容了雙冒號和逗號兩種分隔符因為MovieLens舊版用“::”新版改成了逗號寫死任何一種都會在換數(shù)據(jù)集時翻車。NumberFormatException的catch也是必須的爬蟲拉來的數(shù)據(jù)永遠(yuǎn)比你想象的臟。2.3 評分矩陣的存儲與加載為什么要轉(zhuǎn)置成ItemCF能用的結(jié)構(gòu)實際寫ItemCF時光有userItemMap還不夠因為它要回答“某部電影被哪些人評過分”這是userItemMap的反向關(guān)系。常見做法是啟動時做一次轉(zhuǎn)置生成itemUserMap結(jié)構(gòu)是“電影ID - (用戶ID - 評分)”內(nèi)存開銷比再讀一遍文件要小。public class DataLoader { public static MapInteger, MapInteger, Double transpose( MapInteger, MapInteger, Double userItemMap) { MapInteger, MapInteger, Double itemUserMap new HashMap(); for (Map.EntryInteger, MapInteger, Double userEntry : userItemMap.entrySet()) { int userId userEntry.getKey(); MapInteger, Double items userEntry.getValue(); for (Map.EntryInteger, Double itemEntry : items.entrySet()) { int movieId itemEntry.getKey(); double score itemEntry.getValue(); itemUserMap.computeIfAbsent(movieId, k - new HashMap()).put(userId, score); } } return itemUserMap; } }參數(shù)說明這段是純循環(huán)遍歷不依賴任何框架用Java 8的forEach也能寫但傳統(tǒng)的for在這種雙重遍歷下可讀性更好。轉(zhuǎn)置完以后ItemCF的相似度計算只需要把itemUserMap里的兩個value取出來求余弦連Map結(jié)構(gòu)都幾乎不用改。還有一個值得做的預(yù)處理過濾掉評分記錄少于5條的用戶這些人對相似度矩陣貢獻(xiàn)的是噪聲刪掉以后推薦質(zhì)量會明顯提升——這個閾值在真實項目里要按數(shù)據(jù)量調(diào)數(shù)據(jù)稀疏就降到2到3數(shù)據(jù)稠密就提到10。3. 用Java實現(xiàn)協(xié)同過濾核心相似度計算、UserCF與ItemCF的完整代碼這一章是全篇的重頭戲。我按“相似度函數(shù) - UserCF流程 - ItemCF流程 - TopN排序”的順序給代碼每個函數(shù)都能直接復(fù)制進(jìn)你的工程跑起來。拿到源碼后先改數(shù)據(jù)路徑再調(diào)閾值最后看推薦列表比對著概念空想快得多。3.1 余弦相似度與皮爾遜相關(guān)系數(shù)兩段可直接抄的Java方法相似度是協(xié)同過濾的心臟。最常用的是余弦相似度和皮爾遜相關(guān)系數(shù)。余弦相似度把每個用戶的評分看成一個向量計算兩個向量夾角的余弦值完全同向為1垂直為0反向為-1。皮爾遜相關(guān)系數(shù)相當(dāng)于對兩個用戶各自的評分做中心化也就是減掉各自均值之后再算余弦它能抵消“有人手松全打5分、有人手緊平均給3分”這種偏差。public class SimilarityUtil { public static double cosine(MapInteger, Double a, MapInteger, Double b) { SetInteger common new HashSet(a.keySet()); common.retainAll(b.keySet()); if (common.isEmpty()) { return 0.0; } double dot 0.0; for (int id : common) { dot a.get(id) * b.get(id); } double normA 0.0; for (double v : a.values()) { normA v * v; } double normB 0.0; for (double v : b.values()) { normB v * v; } if (normA 0.0 || normB 0.0) { return 0.0; } return dot / (Math.sqrt(normA) * Math.sqrt(normB)); } public static double pearson(MapInteger, Double a, MapInteger, Double b) { SetInteger common new HashSet(a.keySet()); common.retainAll(b.keySet()); if (common.size() 2) { return 0.0; } double sumA 0.0; double sumB 0.0; for (int id : common) { sumA a.get(id); sumB b.get(id); } double meanA sumA / common.size(); double meanB sumB / common.size(); double numerator 0.0; double denomA 0.0; double denomB 0.0; for (int id : common) { double va a.get(id) - meanA; double vb b.get(id) - meanB; numerator va * vb; denomA va * va; denomB vb * vb; } if (denomA 0.0 || denomB 0.0) { return 0.0; } return numerator / (Math.sqrt(denomA) * Math.sqrt(denomB)); } }參數(shù)說明皮爾遜至少要求2個共同評分否則分子分母恒為0算出來是NaN在推薦鏈路里NaN會一路傳染到排序結(jié)果。還要注意一個細(xì)節(jié)余弦相似度的normA、normB是對用戶全部評分計算的而不是只對共同評分的電影計算。如果你只算共同交集里的模長結(jié)果會把“看過很多電影的用戶”和“只看過幾部電影的用戶”拉到同一水平線上這是我踩過的坑忘一次錯一次。3.2 用Java實現(xiàn)UserCF找TopK相似用戶加權(quán)匯總候選電影UserCF的流程拆成四步取出目標(biāo)用戶的評分遍歷全部用戶算相似度按相似度排序取前K個鄰居最后把鄰居們評過分而目標(biāo)用戶沒看過的電影按相似度加權(quán)匯總。預(yù)測分?jǐn)?shù)用“加權(quán)平均”而不是簡單求和這是為了避免鄰居多的用戶天然占優(yōu)。public class UserCF { private final MapInteger, MapInteger, Double userItemMap; private final int topK; private final int topN; private final double minSimilarity; public UserCF(MapInteger, MapInteger, Double userItemMap, int topK, int topN, double minSimilarity) { this.userItemMap userItemMap; this.topK topK; this.topN topN; this.minSimilarity minSimilarity; } public ListMap.EntryInteger, Double recommend(int targetUserId) { MapInteger, Double targetRatings userItemMap.get(targetUserId); if (targetRatings null || targetRatings.isEmpty()) { return Collections.emptyList(); } MapInteger, Double simMap new HashMap(); for (Map.EntryInteger, MapInteger, Double entry : userItemMap.entrySet()) { int otherUserId entry.getKey(); if (otherUserId targetUserId) { continue; } double sim SimilarityUtil.pearson(targetRatings, entry.getValue()); if (sim minSimilarity) { simMap.put(otherUserId, sim); } } ListMap.EntryInteger, Double neighbors topN(simMap, topK); MapInteger, Double scoreMap new HashMap(); MapInteger, Double weightMap new HashMap(); for (Map.EntryInteger, Double neighbor : neighbors) { int neighborId neighbor.getKey(); double sim neighbor.getValue(); for (Map.EntryInteger, Double rating : userItemMap.get(neighborId).entrySet()) { int movieId rating.getKey(); if (targetRatings.containsKey(movieId)) { continue; } scoreMap.merge(movieId, sim * rating.getValue(), Double::sum); weightMap.merge(movieId, sim, Double::sum); } } MapInteger, Double predictMap new HashMap(); for (Integer movieId : scoreMap.keySet()) { predictMap.put(movieId, scoreMap.get(movieId) / weightMap.get(movieId)); } return topN(predictMap, topN); } private ListMap.EntryInteger, Double topN(MapInteger, Double map, int n) { return map.entrySet().stream() .sorted(Map.Entry.Integer, DoublecomparingByValue().reversed()) .limit(n) .collect(Collectors.toList()); } }邏輯說明minSimilarity默認(rèn)給0.1低于這條線的用戶不做鄰居topK默認(rèn)給20。在稀疏的數(shù)據(jù)集上把minSimilarity降到0.05能多召回不少候選但同時引入噪聲。scoreMap里累加的是“相似度乘以鄰居評分”weightMap里累加的是相似度本身兩者相除得到加權(quán)平均分天然落在1到5區(qū)間不用再歸一化。過濾“已看過的電影”必須做否則推薦列表里出現(xiàn)用戶看過的片子產(chǎn)品驗收這關(guān)就過不了。3.3 用Java實現(xiàn)ItemCF先離線建電影相似度表再在線召回ItemCF和UserCF最大的差別是把“用戶與用戶相似”換成“電影與電影相似”而電影相似度可以預(yù)先離線算好。第一步把userItemMap轉(zhuǎn)置成itemUserMap第二步對兩兩電影算余弦相似度寫入movieSimMap第三步在線推薦時從用戶評分過的電影出發(fā)去相似表里撈候選。下面這段先給出建表和召回兩個方法。public class ItemCF { private final MapInteger, MapInteger, Double itemUserMap; private final MapInteger, MapInteger, Double movieSimMap new HashMap(); private final int numSimilar; private final int topN; private final double minSimilarity; public ItemCF(MapInteger, MapInteger, Double userItemMap, int numSimilar, int topN, double minSimilarity) { this.itemUserMap DataLoader.transpose(userItemMap); this.numSimilar numSimilar; this.topN topN; this.minSimilarity minSimilarity; buildSimilarityTable(); } private void buildSimilarityTable() { ListInteger movieIds new ArrayList(itemUserMap.keySet()); for (int i 0; i movieIds.size(); i) { int movieA movieIds.get(i); MapInteger, Double usersOfA itemUserMap.get(movieA); for (int j i 1; j movieIds.size(); j) { int movieB movieIds.get(j); MapInteger, Double usersOfB itemUserMap.get(movieB); double sim SimilarityUtil.cosine(usersOfA, usersOfB); if (sim minSimilarity) { movieSimMap.computeIfAbsent(movieA, k - new HashMap()).put(movieB, sim); movieSimMap.computeIfAbsent(movieB, k - new HashMap()).put(movieA, sim); } } } } public ListMap.EntryInteger, Double recommend(MapInteger, Double userRatings) { MapInteger, Double scoreMap new HashMap(); MapInteger, Double weightMap new HashMap(); for (Map.EntryInteger, Double entry : userRatings.entrySet()) { int ratedMovie entry.getKey(); double rating entry.getValue(); MapInteger, Double simMovies movieSimMap.get(ratedMovie); if (simMovies null) { continue; } ListMap.EntryInteger, Double similarList topN(simMovies, numSimilar); for (Map.EntryInteger, Double similar : similarList) { int candMovie similar.getKey(); double sim similar.getValue(); if (userRatings.containsKey(candMovie)) { continue; } scoreMap.merge(candMovie, sim * rating, Double::sum); weightMap.merge(candMovie, sim, Double::sum); } } MapInteger, Double predictMap new HashMap(); for (Integer movieId : scoreMap.keySet()) { predictMap.put(movieId, scoreMap.get(movieId) / weightMap.get(movieId)); } return topN(predictMap, topN); } }邏輯說明buildSimilarityTable是雙重循環(huán)只算上三角j從i1開始并在兩邊同時寫入能把計算量減半。movieSimMap的規(guī)模是“存量電影數(shù)乘以平均鄰居數(shù)”1萬部電影最終可能存幾十萬個相似對完全在內(nèi)存可接受的范圍內(nèi)。recommend方法里的numSimilar我通常取10意思是一部電影最多找10個相似電影參與累加避免相似度表過大時每個候選都要遍歷全表。這段代碼的潛在翻車點如果你在recommend里傳入了空的userRatingsscoreMap和weightMap為空最后返回空列表——調(diào)用方要提前做冷啟動判斷不能救到這一步。3.4 TopN排序與推薦列表去重用一個工具方法收尾無論是UserCF還是ItemCF最后都要把候選按得分降序截斷成指定長度。Java里最省事的寫法是stream加sorted加limit但要注意一個細(xì)節(jié)當(dāng)分?jǐn)?shù)相同且條目數(shù)超過limit時stream limit的結(jié)果順序不穩(wěn)定。工程上更穩(wěn)妥的做法是先按“分?jǐn)?shù)降序、電影ID升序”做二次排序保證結(jié)果是確定性的。排序這塊我不建議自己手寫冒泡排序java教科書代碼數(shù)據(jù)量上去之后性能不夠看。用JDK自帶的排序就行private ListMap.EntryInteger, Double topN(MapInteger, Double map, int n) { return map.entrySet().stream() .sorted(Map.Entry.Integer, DoublecomparingByValue().reversed() .thenComparing(Map.Entry.comparingByKey())) .limit(n) .collect(Collectors.toList()); }參數(shù)說明thenComparing(Map.Entry.comparingByKey())是加分項它解決了同分時排序結(jié)果不穩(wěn)定導(dǎo)致的前端展示跳變問題。如果你還在JDK 8以下把stream換成Collections.sort然后手動截斷效果一樣。去重邏輯在核心流程里已經(jīng)做了兩次一是在累加候選時跳過用戶已評分的電影二是在最終推薦表里不重復(fù)插入同一部電影復(fù)合主鍵(user_id, movie_id)兜底防止并發(fā)寫重復(fù)。4. 把算法源碼變成可交付的工程Spring Boot MyBatis的分層與接口算法能跑通只是第一步推薦系統(tǒng)源碼真正值錢的部分在工程化目錄分層是否清晰、數(shù)據(jù)從哪兒來、接口怎么暴露。這一章我按一個常見做法來拆Maven工程打底Spring Boot接HTTPMyBatis管SQL算法層保持純凈。4.1 推薦系統(tǒng)源碼的目錄結(jié)構(gòu)算法包和業(yè)務(wù)包為什么必須分開我見過很多推薦系統(tǒng)源碼最頭疼的是把協(xié)同過濾算法寫在Controller里一個類幾百行既沒法單測也沒法復(fù)用。正確的做法是把算法層和Spring框架徹底隔離目錄結(jié)構(gòu)大致是這樣movie-recommend/ ├── pom.xml └── src/main/java/com/example/recommend/ ├── algorithm/ │ ├── SimilarityUtil.java │ ├── UserCF.java │ ├── ItemCF.java │ └── DataLoader.java ├── entity/ │ ├── Movie.java │ └── UserRating.java ├── mapper/ │ ├── MovieMapper.java │ └── UserRatingMapper.java ├── service/ │ └── RecommendService.java ├── controller/ │ └── RecommendController.java └── RecommendApplication.javaalgorithm包里的類不依賴Spring的Component、Autowired這些注解放到任何Java 8環(huán)境都能直接運(yùn)行。這樣做的直接收益是你可以寫一個main方法單獨(dú)加載MovieLens數(shù)據(jù)調(diào)UserCF不用啟動一個Web容器就能驗證算法效果debug一個推薦邏輯從改代碼到看到結(jié)果不超過10秒。這也是面向?qū)ο缶幊蘪ava里“職責(zé)單一”思想落地算法只負(fù)責(zé)算Service只負(fù)責(zé)編排Controller只負(fù)責(zé)傳輸。pom.xml里需要引入的東西很簡單Spring Boot Web、MyBatis Starter和MySQL驅(qū)動。版本以你自己本地的Spring Boot為準(zhǔn)我習(xí)慣用2.7.x搭配MyBatis 2.x如果是新學(xué)的同學(xué)直接用3.x也一樣接口上沒有大差別。4.2 MySQL表設(shè)計評分表、電影表與推薦結(jié)果表字段和索引這樣定推薦系統(tǒng)要落庫至少要有三張表電影表存元數(shù)據(jù)評分表存用戶行為推薦結(jié)果表存離線算好的TopN。表結(jié)構(gòu)可以直接照抄下面這個字段名我壓到了最少CREATE TABLE movie ( id int NOT NULL, title varchar(255) NOT NULL, genres varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); CREATE TABLE user_rating ( id bigint NOT NULL AUTO_INCREMENT, user_id int NOT NULL, movie_id int NOT NULL, score double NOT NULL, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_movie_id (movie_id) ); CREATE TABLE recommend_result ( user_id int NOT NULL, movie_id int NOT NULL, score double NOT NULL, rank int NOT NULL, update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (user_id, rank) );參數(shù)說明user_rating表的核心是user_id和movie_id兩個索引user_id索引服務(wù)于“給某用戶取全部評分”movie_id索引服務(wù)于“給某電影取全部評分用戶”第二個用途是ItemCF離線計算時的SQL支撐。recommend_result表用(user_id, rank)做復(fù)合主鍵rank直接存1到N意味著同一個用戶新一輪結(jié)果只要按rank覆蓋插入不用先刪后插省一次事務(wù)。score字段存的是協(xié)同過濾算出來的預(yù)測分前端排序直接按它排就行。4.3 Spring Boot接口層Controller保持輕薄Service兜底冷啟動接口層最常見的錯誤是把算法塞進(jìn)Controller再包一層循環(huán)。下面這個例子是標(biāo)準(zhǔn)的三層寫法先看ControllerRestController RequestMapping(/api/recommend) public class RecommendController { private final RecommendService recommendService; public RecommendController(RecommendService recommendService) { this.recommendService recommendService; } GetMapping(/{userId}) public ListMovieVO recommend(PathVariable int userId) { return recommendService.recommendForUser(userId); } }邏輯說明Controller只干一件事把userId參數(shù)取出來交給Service再把Service返回的結(jié)果以JSON形式吐給前端。構(gòu)造函數(shù)注入比字段上加Autowired更利于測試這也是很多公司代碼規(guī)范里的要求。MovieVO是一個輕量DTO只有movieId、title、score、rank四個字段不要直接把MyBatis的實體類返回給前端否則表結(jié)構(gòu)一改接口字段就跟著變坑所有調(diào)用方。緊接著是Service層Service public class RecommendService { private final UserRatingMapper userRatingMapper; private final RecommendResultMapper recommendResultMapper; private final MovieMapper movieMapper; public RecommendService(UserRatingMapper userRatingMapper, RecommendResultMapper recommendResultMapper, MovieMapper movieMapper) { this.userRatingMapper userRatingMapper; this.recommendResultMapper recommendResultMapper; this.movieMapper movieMapper; } public ListMovieVO recommendForUser(int userId) { ListRecommendResult results recommendResultMapper.selectByUserId(userId); if (results null || results.isEmpty()) { ListMovie hotMovies movieMapper.selectHotMovies(20); return MovieVO.fromMovies(hotMovies); } return MovieVO.fromResults(results); } }參數(shù)說明Service層做了冷啟動兜底——如果recommend_result表里查不到這個用戶直接查movie表里的熱門電影榜返回前端的推薦位永遠(yuǎn)不會空。這比在算法層強(qiáng)行判斷更干凈因為接口的語義變成“永遠(yuǎn)有推薦結(jié)果”。selectHotMovies的SQL用“評分人數(shù)和平均分”組合排序ORDER BY score_count DESC, avg_score DESC LIMIT 20不需要join性能就夠。如果要把在線實時推薦也接進(jìn)來做法是在Service里注入ItemCF的Bean把mapper查到的評分記錄轉(zhuǎn)成Map結(jié)構(gòu)喂給算法但這要求評分?jǐn)?shù)據(jù)量小到能在幾十毫秒內(nèi)完成遍歷。數(shù)據(jù)量超過10萬條以后我更建議離線計算落庫再加每日定時任務(wù)別讓算法接口扛實時壓力這就是“離線為主、實時兜底”的常見架構(gòu)。5. 協(xié)同過濾必踩的五個坑冷啟動、稀疏矩陣、評分偏差與性能翻車排查筆記這一章的每條記錄都是真實調(diào)參時會撞見的現(xiàn)象我按“現(xiàn)象、原因、解決”三段寫你照著日志對比就知道問題在哪一環(huán)。5.1 冷啟動新用戶沒有評分推薦結(jié)果永遠(yuǎn)是空的現(xiàn)象剛注冊的用戶調(diào)用推薦接口返回空列表前端頁面在“猜你喜歡”區(qū)域一片空白轉(zhuǎn)化率直接歸零。原因UserCF和ItemCF都依賴歷史評分。用戶沒有任何行為時相似度計算的分母是0任何公式都產(chǎn)出0算法層面無能為力。解決冷啟動階段不做協(xié)同過濾用熱門榜兜底。我前面Service里的實現(xiàn)就是把selectHotMovies結(jié)果返回出去。熱門榜不能簡單用評分人數(shù)排序我一般用“評分人數(shù)×平均分”再乘時間衰減權(quán)重避免老片霸榜。等用戶產(chǎn)生了五六條評分記錄之后再切換回協(xié)同過濾邏輯這是最簡單的漸進(jìn)式冷啟動。5.2 稀疏矩陣兩個用戶只共同看過一部電影相似度卻高達(dá)0.9現(xiàn)象調(diào)日志時發(fā)現(xiàn)一對用戶相似度0.87但他們共同評分只有1部電影。相似表里大量這樣虛高的相似對推薦結(jié)果跑偏。原因余弦相似度在交集樣本極少時統(tǒng)計上不顯著一個共同評分就能把夾角帶得極小相似度虛高。電影站動輒上萬部電影用戶平均評分又少交集為0是常態(tài)交集為1根本不稀奇。解決加置信度門檻當(dāng)共同評分?jǐn)?shù)小于閾值時直接返回0。我在SimilarityUtil.pearson里已經(jīng)寫了common.size() 2就返回0.0實際項目里建議把閾值提到5。同時優(yōu)先使用皮爾遜相關(guān)系數(shù)替代原始余弦因為皮爾遜先做了均值中心化對“共同評分樣本少但絕對分?jǐn)?shù)高”的抗性更好。這條在數(shù)據(jù)稀疏的新站上尤其重要。5.3 評分偏差有人手松全打5分有人手緊只打3分余弦相似度直接失真現(xiàn)象用戶A給所有電影打5分用戶B同樣幾部電影打4分余弦相似度依然算得很高可兩人的真實口味可能完全相反。原因余弦相似度把絕對分?jǐn)?shù)當(dāng)成向量方向來算沒有減去每個用戶的平均分。手松和手緊在絕對分?jǐn)?shù)上差了整整一個常數(shù)偏移這個偏移在余弦公式里沒有被消除。解決改用皮爾遜相關(guān)系數(shù)等價于把每個用戶的評分先中心化原分?jǐn)?shù)減均值再算余弦。我的SimilarityUtil里兩個方法都寫了工程里默認(rèn)走pearson就對了。如果你堅持用余弦那就先做歸一化我可以把“score - userAvgScore”存入Map后再交給余弦方法。5.4 熱門電影屠榜推薦結(jié)果全是全局爆款多樣性和個性化同時歸零現(xiàn)象離線計算結(jié)果里Top10推薦總是那幾部評分人數(shù)最多的電影每個用戶的列表大同小異運(yùn)營抱怨“推薦沒有差異性”。原因熱門電影被大量用戶評分它們和所有電影都容易產(chǎn)生相似關(guān)系用戶在評分過的電影里去撈相似候選熱門電影出現(xiàn)的頻率極高累加積分碾壓小眾片。解決累加權(quán)重時加入熱門懲罰。常見做法是對候選電影的相似度乘上一個衰減系數(shù)sim / Math.pow(1 Math.log(1 itemUserMap.get(movieId).size()), 2)這個系數(shù)隨評分人數(shù)上升而下降。還可以在后處理里做類型約束按genres分組每組最多選3部保證TopN里有喜劇也有懸疑而不是清一色的動作大片。這一步是推薦結(jié)果從“能用”到“像樣”的分水嶺。5.5 性能翻車循環(huán)里查庫導(dǎo)致N1查詢一次推薦接口把數(shù)據(jù)庫打掛現(xiàn)象一次推薦請求發(fā)出后數(shù)據(jù)庫慢查詢?nèi)罩纠锍霈F(xiàn)兩三百條SQL接口耗時8秒QPS一高M(jìn)ySQL連接直接打滿。原因典型的N1問題。常見寫法是在算法里遍歷用戶列表每次循環(huán)調(diào)一次mapper查詢評分比如for (userId : allUsers) { userItemMap userMapper.selectRatingsByUserId(userId); }。用戶量一上來這個循環(huán)就是災(zāi)難。解決把行為數(shù)據(jù)一次性加載進(jìn)內(nèi)存。在Spring Boot啟動時用PostConstruct或ApplicationRunner執(zhí)行一次全量load把評分記錄組裝成userItemMap和itemUserMap保存在單例Bean里接口只從內(nèi)存取數(shù)。數(shù)據(jù)量超過百萬條時改為離線Spark或定時任務(wù)預(yù)計算后再落recommend_result表在線接口絕不碰評分明細(xì)表只查推薦結(jié)果表。這條不只是性能問題還是一個架構(gòu)取舍推薦結(jié)果表里只有每個用戶前20條結(jié)果查詢走主鍵P95響應(yīng)時間能壓到10毫秒以內(nèi)。6. 驗證推薦結(jié)果是否靠譜離線切分、覆蓋率與K值調(diào)參的進(jìn)階收尾推薦系統(tǒng)源碼寫完最容易被忽略的一步是驗證。沒有驗證手段你就分不清“參數(shù)調(diào)好了”和“參數(shù)調(diào)順手了”。我最后分享一個每次都會做的離線驗證流程和兩個指標(biāo)。先把評分?jǐn)?shù)據(jù)按時間切分按timestamp排序前80%作為訓(xùn)練集后20%作為測試集。協(xié)同過濾只用訓(xùn)練集計算相似度和推薦然后用測試集里用戶真實看過的電影和推薦結(jié)果做比對。如果推薦結(jié)果里出現(xiàn)了用戶真實看過的測試集電影說明這次推薦是命中的。命中數(shù)除以測試集電影數(shù)就是召回率再算一下推薦結(jié)果覆蓋了電影全量的多少比例得到覆蓋率。這兩個數(shù)字一個衡量準(zhǔn)確度一個衡量多樣性。K值和相似度閾值的調(diào)參法固定minSimilarity為0.1把K從5、10、15、20依次跑一遍記錄每組的召回率和覆蓋率。你會發(fā)現(xiàn)K小的時候精度高但覆蓋面窄K大了以后結(jié)果趨于熱門化。我在做電影推薦這類的經(jīng)驗值是K20到30minSimilarity0.1到0.2如果你的數(shù)據(jù)更稀疏K往下調(diào)、minSimilarity往下調(diào)數(shù)據(jù)更稠密就反過來。調(diào)參順序是先調(diào)K再調(diào)minSimilarity最后才調(diào)熱門懲罰系數(shù)因為K對結(jié)果的影響最直接。最后一個進(jìn)階技巧是存一份movieSimMap的序列化緩存。ItemCF建電影相似度表在幾千部電影時需要幾十秒可能每次重啟都要等。常見做法是用Java自帶的ObjectOutputStream把movieSimMap寫到本地臨時文件啟動時先檢查文件存在就反序列化加載不存在才重建。我會在代碼里注明緩存的失效條件只要評分?jǐn)?shù)據(jù)更新了就要刪掉緩存文件重新生成否則推薦永遠(yuǎn)不會反映新行為。這套源碼我自己交過課設(shè)也改過生產(chǎn)環(huán)境的需求最大的教訓(xùn)是協(xié)同過濾不是裝上去就完事的黑匣子它需要你把每一個閾值當(dāng)成可配置的參數(shù)再把驗證指標(biāo)當(dāng)成調(diào)參的準(zhǔn)繩。推薦結(jié)果能打60分還是90分差別往往不在算法本身而在于你有沒有把冷啟動兜底和熱門懲罰做到位。希望幫到你。本文還有配套的精品資源點擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
97久久精品| 99热亚洲精品| 亚洲激情AV| 嫩BBB搡BBBB榛BBBB| 婷婷伊人五月| 色婷婷丁香六月| 超碰啪啪网| 91婷婷| 99思思热只有在这里看| 婷婷五月天 偷拍| 久久无意婷婷| 久久精品熟女亚洲AV麻豆| 5五月综合网亚洲| 99热国品免费| 久久九九网| 丁香5月啪啪| 成人av中文字幕| www色哟哟| 丁香五月婷婷网| 综合激情站| 欧洲亚洲最新精品| 久久99激情| 另类精品视频在线观看| 久久五月天色婷婷| 99热主页日本| 婷婷天堂综合| 激情五月天在线观看婷婷| 《丁香激情综合久久伊人久久》影视在线观看 -高清预告手机免费播放 -三妹影院 | 中文字幕不卡+婷婷五月| 婷婷五月天最新网址| 狠狠精品干练久久久无码中文字幕| 五月天六月色| av在线观看网站| 艹B高清无码| 久久九色| 中文字幕无码人妻少妇免费视频| 婷婷六月色| 91久久| 婷婷五月久久| 五月婷婷丁香社区| 久99久99精品免| 亚洲成人噜噜| 九九热婷婷| 婷婷六月激情综合| 99久久久久久www| 97婷婷五月天| www.yw色| 日日夜夜婷婷| 疯狂做受XXXX高潮A片| 色欲天天综合网| 色婷婷97| 六月丁丁香| 超碰超碰在线| 少妇被躁爽到高潮无码文 | 婷婷综合九月| 无码色色色| 大香蕉婷婷久久| 五月婷婷综合网| 婷婷五月天堂一本在线| 99精品国产在热久久婷婷| 色 色 色综合com| 激情婷婷色五月| 亚洲五月色| 99精品大片| 亚洲婷婷免费| 色综合婷婷| 丁香婷婷五月| 国内精品免费一区二区2009| 婷婷五月丁香欧洲| 免费99情趣网视频| 99久久五月婷婷| 日本色色网站| 最近中文字幕大全免费版在线 | 国产精品国产| 丁香五月狠狠综合欧美| 超碰资源在线| 成人国产欧美大片一区| 99亚洲视频| 高清无码网址| 婷婷的色色五月天| 色五月aV| 婷婷五月天小说网| 婷婷五月欧美| 中文人妻主播久久| www.五月.com| 91九色在线| 国产内射婷婷| 入口五月婷婷六月香| 亚洲婷婷五月草久| www.99婷婷| 五月天激情小说网| 色久女| 五月丁香手机在线| 天天干,夜夜爽| 9l视频自拍9l九色成人| 伊人婷婷99热精品| 九九热只有这里精品| 91人妻视频| 夜夜久久综合网| 欧美日韩成人在线| 婷婷五月天奸女| 蜜臀A∨在线水帘洞| 婷婷黄色五月| 激情九九综合网| 91操网| 日本不卡高字幕在线2019| 99re视频在线| 丁香社区婷婷五月| 一级黄色影片| 啪啪激情网| www.日日夜夜| 丁香五月天视频| 丁香五月天婷婷91| 99热中文字幕久久| 婷婷最新地址| 五月伊人视频在线看| 天天操比比| 五月天大香蕉| 久月丁香爱婷婷综合| 色婷婷色99国产综合精品| 精品一二三区久久AAA片| 综合超碰熟| 亚洲激情高潮| 99国产精品久久久久久久久久久| bbwcuckold精品熟妇| 色色色色网| 99热这里只有精品最新| 免费视频在线观看的网站| 91久久精品无码一区二区三区| 五月丁香啪啪拍| 日韩 中文 欧美| 大香蕉福利导航| site:hcxsz888.com| 天天射影院| 亚州在线中文字幕| 这里只有精彩视| 久久久99精品免费观看| 五月婷婷综合色啪首页| 99久久九九视频| 丁香婷婷人妻| 青草视频在线播放| 九九精品视频在线6| 大香蕉啪啪啪| 久久av电影| 国产精品扒开腿做爽爽爽A片唱戏| av色婷婷| 99爱在线精品视频免费观看| 亚洲婷婷五月草久| 亚洲无码影音| 五月婷婷av| 欧美精品熟女一区二区| 婷婷色情五月| 欧洲亚洲免费视频9| 日韩 mm 不卡| 日本系列_4页_777FP| 日韩久久欧亚| 久热综合| 能看的AV网站| 日逼影音先锋AV男人资源站| 97五月天| 激情九月婷婷| 五月婷婷综合网| 都市激情蜜桃婷婷五月天 | 影音先锋天天日| 久人操| 六月婷婷久久| 丁香五月深爱五月婷婷| 九月婷婷人人操人人舔人人爱| 蜜乳A√| 天天爽夜夜操| 色中色综合| 99噜噜噜| 久操热| 丁香桃色综合网| 99在线精品免费视频| 日韩成人精品一区久久久久| 99草在线免费观看视频| 碰碰女| 色婷婷基地| 色婷婷五月天| 91成人电影| 色欲天天综合| 狠狠干青青草| 99精品热视频| 日韩av免费版| 激情六月婷婷| 天天草天天摸| 日日干夜夜撸夜夜骑 | 亚洲传媒在线观看| 九九热最新地址| 丁香5月综合啪啪| 开心五月婷婷伊人| 五月天婷婷久久| 99黄色| 97热久久| 日本操天堂| 色播播五月| 午夜丁香| 99九精品| 任你弄在线视频免费| 91色逼| WwW天天干| 色约约视频一区二区三区四区五区 | 超碰亚洲天堂| 九九热99精品| 婷婷丁香日韩五月| 啊v视频在线观看| 伊人五月丁香| 五月天在线视频尤物视频在线看| 亚洲激情AV| 久热伊人91| 色情婷婷| 欧美色九| www,天天干| 婷婷色播色五月五色五月天色妇| 久久图色4| 激情综合亚洲| 久久伊人大香蕉| www.亭亭五月天| 97人人射| 热久久91| 综合激情在线| 婷婷五月丁香91| 亚洲国产精品VA在线看黑人| 色色色网站| 99热精品在这里| 青青草护士中出内射-欧美电影在线天堂新版| www.99精品视频| 操操操97| 亚洲中文字幕在线观看| 强辱丰满人妻HD中文字幕| 少妇人妻人伦A片| 五月婷婷就去色| 色综合久久88色综合天天99| 99热99极品观看| 色欲AVV| 激情深爱五月天| 色色丁香婷婷综合| 五月丁香综合啪啪| 婷婷五月激情五月激情| 丁香五月天堂网| 六月丁香色色| 婷婷精品视频| 婷婷俺去也| 97精品在线| 欧美婷婷成人| 九热免费视频| 另类天堂| 天天爽天天干| 美女婷婷激情亚洲| 9l久久久视频| www五月天com| 亚洲性爱电影| 中文字幕婷婷| 99丁香五月婷| 天天成人综合视频| 色五月婷婷内射| 色综合天天天天做夜夜| 99视频| 99视频在线精品| 婷婷五月另类网站| 色综合久久99色| 九九视屏| 久久这里只有精品热在99| 91人人操人人爱| 超碰色综合| 五月婷婷亚洲| 97在线精品| 日本精品人妻无码77777| 激情六月天| 最近中文字幕大全免费版在线 | 丁香五月婷婷操逼| 丁香婷婷色| 97碰免费视频在线| 国产精品色色色色| www.狠狠| 99久久久久| 色色色综合网| 97超碰99热99| 色五月婷婷基地| 色色色色欧洲| 激情五月天色婷婷| 日韩综合久久| 超碰成人黄色网| 草榴视频黄色网| 99色在线免费观看视频| 热99精品视频在线观看| 日韩在线婷婷五月天综合| 久色婷婷200| 色婷婷五月色| 97碰精品| 激情综合青草| 99无码黄色视频| www.久久综合| 99国产精品久久久久久久久久久| 色激情五月| 人人草成人视频| 婷婷五月天亚洲激情戏精品| 色婷久| 久久综合九九| 激情五月色综合网| 久久一二三视频| 66色在线日韩| www.色五月| 五月天AV大香蕉| 久久久精品99亚洲综合| 九色啦蜜臀| 97福利视频| 久碰久| se99高清无码| 丁香五月婷婷综合精品素人| 五月天丁香婷婷久久九| 婷婷六月丁香激情| 思思热视频在线观看| 9久热| 播丁香五月婷婷欧美| 香蕉大综综综合久久| 色五月激情问网站| 六月婷婷激情图片| 欧美激情伊人| 99亚洲无码| 色五月婷婷综合| 色婷婷最新域名| 丁香婷婷丁香五月欧美人| 五月天婷婷社区| www.五月天| 9福利性视频欧美| 激情五月婷婷综合视频| 99热精品在线| 色五月综合婷婷久久综合婷婷久久综合婷婷久久综合婷婷久久 | 女人天堂av| 婷婷午夜综合| 91人操人人人操人| 激情婷婷网| 色综合久久伊伊婷婷五月| 色婷婷综合久久久久| 六月丁香婷婷爱| 五月激情综合婷婷| 成人综合网站| 极品 少妇 内射| 丁香色婷婷| 丁香久月| 五月丁香好婷婷A片网| 桃色五月婷婷| 婷婷五月天男人影院色色网| 久99视频| 99re思思精品视频在线观看| 夜夜骑夜夜操| 婷婷精品视频| 在线成人视频免费| 欧美激情xxxXX| jiqingliuyuetian| 操操操操操操婷婷五月天| 婷婷五月丁香影院| 99热在这里只有免费精品| 婷婷五月天激情开心网| 丁香色情五月综合激情| 婷婷综合色播网| 在线看AV| 五月丁香淫淫婷婷婷| 国产成人精品123区免费视频| 欧美色五月| 婷婷操久久| 欧美伊人9| 激情綜合W W W,激情五月天| Av免费网站在线| 五月婷婷久| 色色色九九九五月婷婷| 亚洲最大视频| 99色视频在线观看最新| AVDV久久| 久热这里只有精品视频6| 国产精产国品一二三在观看| 台湾佬天天日丁香婷婷五月天| 中字幕视频在线永久在线观看免费 | 青草激情在线| 国产亚洲av片| 久久久久激情| 深爱激情小说五月婷婷| 99热黄| 超碰1999| 国产熟女一区二区三区五月婷| 亚洲综合在线播放| 丁香无五月网| 九九色video| 99成人在线观看| 99视频在线观看网址| www.五月天色色.com| 欧美六月| 婷婷五月综合性爱| 91人人操.COM| 五月丁香天堂网婷婷| 另类在线免费视频| 婷婷五月天六月丁香| 99熟女视频| 天天精品视频免费观看| 女人天堂 AV| 香蕉97碰碰碰超视精品| 综合激情五月丁香| 丁香婷婷激情六月五月开心| Av性爱网站| 天天干天天av天天射| 色香欲综合| www,五月天com| 狠狠婷婷综合| 四色五月婷婷| 五月天播播中文字幕| 五月丁香久人妻中文| 丁香五月五月婷婷欧美大香蕉| 国产精品热搜丁香五月婷婷| a色色色色色| 狠狠色噜噜狠狠狠777奇米| 婷婷综合视频| 蜜桃五月天| 欧美操人| 婷婷丁香五月91| 日日夜夜干| 色在线视频网2025| 狠色狠色狠色狠色狠色网| 超碰A V在线| 日韩成人无码| 超碰人人操在线| 99热骚货| 五月香蕉综合| 欧美日综合| 国产人人操| 久久九九国产精品怡红院| 人妻无码精品一区| 甈你aaaaa| 亚洲九九夜夜| 亚洲无码影音| 久久免费精彩视频| 久久久8| 激情五月婷婷开心网| av九九| www色哟哟| 91丨九色丨熟女高潮| 99精品久久久久久久婷婷久久| 99在线公开视频| www.seqingwuyuetian| 99无码超碰| 丁香婷婷十月| 成人无码精品1区2区3区免费看| 色播丁香婷婷五月激情| 伊人婷婷激情| 亚洲综合视频天天精品| 玖玖综合色| 婷婷玖玖丁香| 丁香五月伊人| 婷婷综合性爱网| 97人人草| 五月综合激情| 天天玩夜夜操| 人妻22p| 五月丁香激情综合网| www.狠狠操.con| 无码人妻激情| 久久久97| 色婷婷综合久久久久| 久色大香蕉| 不卡在线视频| 男人的天堂在线婷婷| 97精品人人A片免费看| 亚洲综合色网| 无码少妇高潮喷水A片免费 | 亚洲精品字幕在线观看| 色情综合| 日本色婷婷| 丁香婷婷久久 | 99性爱| 亚洲无码成人性爰网| 天天做天天爱天天爽夜夜揉| 婷婷欧美| 噜噜噜久久| 色婷婷影院| 97影院一级片| 91精品婷婷国产综合久久| www99精品| 婷婷色九月| 99在线视频资源| 色香蕉影院| 99热综合网| 国产成人高清| 99热这里只有精品55| 二色av| 深爱激情五月天| 精品国产乱码久久久久夜深人妻| 97色精品视频| 人人操操97| 人人草碰| 丁香5月激情网| 久久一热免费视频| 国产精品视频久久99| 欧美黄色韩日网| 色99视频| 婷婷五月天小说| 成人精品视频99在线观看免费| 91九九九九| 久久五月天激情| 久久44| 五月婷婷婷| 99热热这里只精品996小说| 97久久精品| 《战争与艾拉》完整版| 狠狠干伊人| 亚洲天堂aaaa| 深爱丁香激情| 久久五月天婷婷| 超碰在线视屏| 九九人人操| 操大屄五月天视频| 亚洲无线视频| 色婷婷色五月色丁香| 婷婷丁香18| 亚洲成人免费电影| 九日日夜夜69| 深爱五月激情网| 丁香六月无码| 综合激情视频| 成人av观看| 婷婷五月天亚洲色| 99热1| 日韩精品无码一区二区| 性热视频99精品| 婷婷在线播放av| 五月天色网站| 97人人草| 蜜乳AV成人| 色狠狠五月天| 日日噜噜夜夜狠狠久久丁香六月| 涩五月婷婷| 色五月美女| 97人人干| 综合婷婷五月天| 超碰九九热| 狠狠干.com| 久99视频在线观看| 丁香五月天天高清在线| 国产又黄又爽又色的免费| 91九色超碰正在播放| 久久婷婷五月国产色综合激情| 五月激情婷婷国产精品久久久久久 | 69超碰在线| 色丁香久久| 夜夜综合色| 五月婷在线观看| 婷婷激情五月天激情小说| 六月丁香婷婷综合色播| 国产激情AV| 99热大| 一二三区视频韩国| 六月婷婷综合| 丁香五月综合久久八| 日韩在线99| 九月婷婷激情久久| 五月丁香六月婷婷无码| 婷婷色色综合| 日韩av干| 在线看九一V图片| 婷婷五月天丁香| www99热| 天天肏在线观看| 激情五月婷婷综合网| 五月天色色色| 久久欧洲综合网| 国产成人精品一区二三区熟女在线| 日韩狠狠色| 思思热久热| 五月激情婷婷四射| 五月婷婷网五月在线| 国产露脸150部国语对白| av 一区三区四区| 亚洲综合九九| 97干在线视频| 久久丁香五月婷婷| 天天爱天天日| 五月丁香综合激情网| www.99热在线观看| 日韩欧洲亚洲| 视频这里只有精品| 久久五月婷| 激情五月图| 五月综合激情网| 天天综合亚洲综合网天天αⅴ| 色婷婷导航| 亭亭丁香久久五月| 9国产在线视频| 99色 色| 色九九九综合| 五月丁香成人视频| 96精品久久久久久久久| 九九婷婷综合| 色色丁香| 影音先锋91网站在线观看| 婷婷六月网| 色九九综合色| 99综合网| 99er这里只有精品视频| 极品人妻VIDEOSSS人妻| 婷婷五月花西瓜| 99热99思午夜精品| 激情婷婷丁香五月天| 99久久免费性爱视频`| 伊人久久婷婷| 五月天俺去也| 丁香六月啪| 日日日日日| 色女伊人| 五月丁香激情综合| 91精品激情9| 97 A I色色| 婷婷情色五月天| 色墦五月丁香| 夜夜爽天天日| 大香蕉婷婷丁香视频在线| 五月天狠狠| 丁香五月婷婷欧美成人色图| 色你久久| 精品香蕉99久久久久网站| 天天爽夜夜爽夜夜爽精品视频| 成人版视频在线观看| 色爱五月天| 性色99| 色情五月天丁香社区| 激情五月天色播| 99久久激情视频| 色五月天丁香| www.夜夜爱.com| 另类小说五月天| 综合图区激情| 另类五月婷婷| 久草网大香视频| 97在线精品| 五月婷婷日| 五月丁香婷婷五月色| 色婷婷丁香社综合| 激情五月婷婷老师| 亚洲婷婷免费| 天天射影院| 久草xx性爱视频| 99热这里是精品| 日本婷婷色| 五月婷婷激情综合| 九色七七| 激情五月天婷婷丁香 | 精品久久久久成人码免费动漫| 九九热视频在线观看| av在线超清中文| 9l视频自拍九色9l视频在线观看| 色综合婷婷99| 午夜69成人做爰视频| 天天综合 99久久婷婷| 思思久日精品视频| 五月丁香六月激情综合啪啪| 色婷婷婷婷| 激情婷婷九月| 狠狠狠狠青草| 在线五月婷| 风流少妇A片一区二区蜜桃 | 色和综合网| 人妻久久久| 中文字幕在线日亚州9| 天天插天天插天天插天天插| 激情久久五月网| 侠女刀之记忆电影在线看免费| 天堂综合久| 99ri国产精品| 色亭亭丁香五月天| 婷婷碰碰| 人人操婷婷| 婷婷99狠狠躁天天久久久九九九| 99久热| 婷婷金品综合视频| 激情综合在线观看| 丁香婷婷性爱| 99ri在线视频| 超碰在线人人| 国产免费一区二区在线A片视频| 婷婷娌伦网| 99久久网站| 97亚洲婷婷| 人人操人人爰人人一天天碰夜夜拍夜夜爽-中国A级毛片天天看天天谢… | 婷婷大香蕉| 亚洲成人综合在线| 99综合| 伊人激情综合网| 天天日夜夜| 91九色在线视频| 丁香激情五月| 97久久久久| 五月激情小说网| 激情网五月| 亚洲综合激情五月久久| 无码日本精品XXXXXXXXX | 婷婷五月天福利| 五月丁香婷婷色啪| 日韩AV在线电影| av网站免费在线| 五月丁香综合久久夜夜| 九色地址91视频| 婷婷丁香97| 激情五月婷黄版| 91人人妻人人操| 久色网| 激情五月天婷婷激情| 噜色精品| 色偷偷狠狠| 99精吕视频在线观看了| 亚洲成人影视在线观看| 综合激情五月天| 五月伊人91| www.爱婷婷.com| 九月综合| renre人人操国产超碰在线 | 亚洲精品又粗又大又爽A片| 亚州美女| 色色九九五月天 | 五月天堂在线| 影音先锋偷偷色男人站| 五月天久久久| 婷婷激情五月天激情小说| 色播婷婷五月天| 国产日日夜夜操| 26uuu欧美日本| 天天影院色| 国产免费一区二区三州老师F1……| 久久婷网| 亚洲AAA| 久久婷婷五月| 综合网色| 大香伊人婷婷| 婷婷久久久久久久| 99热色精品| 亚洲欧美婷婷五月色综合| 丁香啪啪中文字幕| 99在线观看视频免费| 婷婷瑟瑟五月天| www色五月| 日本9区视频| 视频免费精品免费精品免费精品免费精品免费精品免费精品免费99 | 超碰人人99| 丁香五色月婷婷网| 日韩精品一区二区亚洲AV观看 | 亚州欧美国产久精国产99综合视频| av操一操| 97人妻超级碰碰碰碰碰| www.婷婷亚洲基地| 天天干天天爽天天操| 婷婷色六月| 97婷婷五月激情六月丁香伊人| 国内婷婷丁香社区在线播放| 五月丁香啪啪网| 精品久久久久成人码免费动漫| 另类视频综合| 色亭亭五月天丁香综合AV - 百度 - 百度| 丰满少妇猛烈A片免费看观看| 色伊人婷婷| 管管補管管紱| 婷婷五月天久久久| 99九九热在线观看| 婷婷大乡焦噜噜| 婷婷五月精品| 1010日日无码| 少妇高潮呻吟A片免费看软件| 激情五月综合网最新| 天天操婷婷| 超碰99热精品在线| 婷婷成人五月天一区| 亚洲无码色色| 亚洲精品无码久久| 在线成人网站| 九色七七| 免费婷婷| 色色九九五月天 | 日本妈妈乱| 九九色99| 亚洲av免费在线| 日韩综合久| 日韩AV成人电影| 国产日日操夜夜操的肉棒视频| 五月丁香网站| 操逼123网| 少妇人妻丰满做爰XXX| 婷婷五月天手机版视频| 婷婷五月影院| 99re久热只有精品6在线直播| 成人在线日韩| 99热成人精品| 国产精品A成V人在线播放| 成人超碰AV| 人妻体体内射精一区二区| 这里只有精品视频国产| 狠狠操狠狠爱| 日本va视频| 久久免费少妇高潮99精品| 五月综合色播播丁香婷婷 | 五月视频日本免费观看| 午夜性做爰电影| 呦呦v线| 曰韩少妇内射免费播放| 在线播放成人网站| 青青草激情网| 天堂婷婷丁香六月网| 亚洲精品V天堂中文字幕| 色色色五月婷婷| 五月婷婷色色| 久久久精久人妻| 五月婷九九草| 久9视频免费播放| 六月色色| 中文字幕丰满孑伦无码专区| 五月色网| 99热插| 九九99九九99九九99视频网| 五月丁香婷婷网网网网| 五月天精品| 国产色五月| 丁香六月婷婷社区| 99热精品在线| 色婷婷丁香AV综合| 五月久久网| www.操.com| 日本成人噜噜噜噜噜| 激情五月婷婷啪啪| 五月亭亭直播| 夜丁香五月婷婷| enecarbon-materials.comWu染请涟系Bao护@wip1688 | 久久这里有精品| 青青福利网| 77777亚洲午夜久久| 大天天伊人| 99视频精品视频| 十二区无码| 97热这里只有精品| 婷婷色成人| 91人妻PORNY九色大屁股| 亚洲欧洲中文日韩久久AV乱码| 狠狠操狠狠插| 激情综合综合综合| 91凹凸在线| 人妻丰满精品一区二区A片| 婷婷综合激情五月中文字幕| 超碰京东热av男人的天堂| www.yw尤物| 天天综合网网欲色| 九九碰九九爱97超碰| 亚洲成人av在线观看| 欧美色图天堂网| 久久婷婷五月天综合| 在线中文字幕av| 五月婷婷综合在线视频| 久久激情五月| 九九亚洲视频| a69在线视频| 啪啪夜久久| 精品AV无码超碰| 欧美色色色色色| 色婷婷偷拍| 色婷婷先锋| 爱爱色五月天| 91精品久久久久久久久久久久| 综合久久五月| 免费做A爰片77777| 丁香五月伊人| 99九九视频精彩在线| 亚洲va欧美va国产综合久久久| 99色热| 久9精品视频| 大香焦A∨| 五月婷婷狠狠干| Www.狠狠| 亚洲综合视频一下| 亚洲精品网站色视频| 色九月欧美| 欧洲区自拍| 强辱丰满人妻HD中文字幕| 超碰碰碰碰| 9l视频自拍9l视频自拍九色学生| 天天干夜夜想| 狠狠草综合网| 婷婷五月天激情AV影院| 婷婷综合五月激情| 婷婷成人在线| 播五月婷婷开心| 亚洲综人色综网| 啪啪99| 六月婷婷久久| 丁香色影院| 99国产精品久久久久久久久久久| 婷婷丁香久久| 在线观看av网站| 午夜婷婷久久 | 99精品在线| www.色九月| 激情图片五月天| 婷婷五月天美女21p| 99热6色| 老司机伊人| 人人看人人摸人人| 激情亚洲网| 婷婷综合色五月天| 人人爽欧美婷婷久久久五月丁香 | 综合久久综合五月天婷婷| 夜夜嗨一区二区三区直播内容| 精品一二三区久久AAA片| 大香蕉AV在线| 大香蕉综合视频在线| 亚洲精品久久久无码| 丁香五月花| 黄桃AV无码免费一区二区三区| 夜夜嗨一区二区三区直播内容 | 五月婷婷六月天| 免费观看18视频网站| 全部老头和老太XXXXX| 久久婷婷七月丁香| 日日夜夜亚洲一区| 欧美日韩五月婷婷| 91激情五月开心| 狠狠综合久久| 婷婷五月蜜桃成人桃色丁香| 伊人婷婷激情| 色婷婷狠狠干芒果TV| 五月天丁香婷婷社区| 九九热自拍| 大香蕉婷婷| 超碰免费人| 久艹伊| 久久精典| 婷婷性爱无码视频| 天天谢天天操| 综合久久影院| 五月丁香婷婷成人网| 国产古装妇女野外A片| 色五月丁香A欧美com| 色情婷婷。| 91狠狠综合久久久久久| 日韩按摩二区| 高清无码入口| 久久久97| 色天使久久综合| 538任你爽| 婷婷五月成人有| 天天做天天爱天天玩夜夜爽| 色婷婷五月天在线观看| 亚洲色五月天| 97操在线| 九色婷婷| 丁香影院五月综合| 国产亚洲网站在线| 激情五月天婷婷图| A久网| 九月丁香婷婷综合| 超碰人人摸人人操| 大香蕉婷婷久久| 99热这里精| 日本一毛片| 亚洲成人无码专区| 香蕉久久六月| 蜜桃婷婷丁香| 成人亚洲精品| 9|在线观看视频| 中文字幕在线播放视频| 婷婷丁香五月亚洲免费| 色色婷婷丁香| 97成人丁香| 大香蕉啪啪啪| 五月婷婷日| 亚洲精品无AMM毛片| 国产欧美第五十五页| 久久久久人无码人妻| 99精品久久| 婷婷五月天大香蕉在线视频观看| 色婷婷五月六月丁香综合视频| 久久66精品| 九九热在线视频观看| 丁香五月天婷婷91| 日韩AAA| 成人丁香| www.97干视频| 激情五月亚洲| 激情五月天在线视频| 999久久久国产精品| 天天网站天天爽| 色色激情五月天| 色情五月天导航| 五月精品免费XXX| 婷婷综合网| 国产9色在线/日韩| 九九热这里| 九九伦子片| 婷婷涩涩网| 亚洲综合五月天| 久/久精品99看9| 超碰人人干| 《丁香激情综合久久伊人久久》影视在线观看 -高清预告手机免费播放 -三妹影院 | 色色丁香| 91精品婷婷国产综合 | 日本三级第一页| 亚洲成人色五月婷婷综合| 欧美婷婷日本| 五月丁香综合成人社区| 丁香五月天在线观看| 亚洲欧美日韩另类| 色噜综| 国产精产国品一二三在观看| 久久五月天综合视频网站| 丁香婷婷五月色成人网站| 91久久免费| 久久av电影| 国外亚洲成AV人片在线观看| 色久婷婷网| 五月丁香激情综合网| 韩日在线熟女| 丁香五月自拍| 99精品热| www.色婷婷| 狠狠爱综合| 久久九九怡红院| 九九综合精品| 五月丁香综合啪啪| 五月丁香啪啪网| 综合五月天亚洲婷婷| 五月婷在线| 这里只精品| 98国产精品综合一区二区三区| 色爱99| ..真实国产乱子伦毛片 | 婷婷五月综合色中文字幕| 婷婷涩涩五月天| 精品人妻在线| 五月婷婷色综图片| a网站免费观看| 九九激情| 99色播| 青青草国产亚洲精品久久| 亚洲婷婷开心五月| 国产在线网| 激情五月婷婷老师| 色五月婷婷综合在线| 91无码视频| 激情综合网之激情五月| 少妇性BBB搡BBB爽爽爽电影| 色性五月天| 亚洲操B视频| 亚洲AV成人精品日韩在线播放| 色情·com| 激情五月婷婷| 五月婷婷激情综合网 | 五月丁香亭亭A片| 久久99大全| 狠狠夜夜五月丁香| 玖玖婷婷免费| 久久婷婷色综合| 99热99在线| 任你爽在线视频| 日本久久人| 日本色婷婷综合| 婷婷五月天性爱视频| 天天色99| 久色成人| 日韩av高清| 婷婷五月电影院| va中文资源在线观看| 综合 蜜月 婷婷| 99综合网| 天天操,天天插| 婷婷久久内射| 五月天大香蕉| 深爱激情丁香| 日本超碰在线| 天天干在线播放| 色婷婷99| www.26uuu.com亚洲电影| 成人av播放| 亚洲欧洲中文日韩久久AV乱码| 久久久精品人妻| 激情五月深爱五月| 色yeye欧美| 五月激情影院| 久久久久久人妻久久久久久久久久人妻久久久 | 99这里只有精品在线观看| www.com任你艹| 在线播放成人网站| 婷婷六月丁香欧美视频在线| 丁香五月综合激情久久潮喷| 久久中国毛毛片爱久久| 开心深爱激情网| 欧洲色色| 能看的av片| 久久婷婷五月天激情新地址| 色九四色| 亚洲精品99| 久青操| 色5月婷婷| 婷婷五月丁香五月丁香| 丁香六月婷婷社区| 专区无日本视频高清8| 大香蕉婷婷| 婷婷精品性视频| 婷婷另类开心| 久久婷婷婷| 香蕉99网| 操大屄五月天视频| 日本天天色| 婷婷五月激情的图片| 色宗合久久五月婷婷| 丁香五月激情六月欧亚激情综合导航| 一本九九色| www久久久久久久久久久| 岛国AV网| 色色色网站| 日日日日操| 五月天激情图片| 激情婷婷综合网| 色综合婷婷99| 国产特级毛片AAAAAAA高清| 亚洲日日日| 久99热| 九九热精品视频在线观看| 五月婷丁香亚洲| 无码人妻少妇色欲AV一区二区| 91精品婷婷国产综合久久| 九九久久网| 色99综合视频| 9999色色色色| 情五月亚洲婷婷| 99在线精品视频免费| 就是色婷婷五月亚洲色| 色碰碰| 久99热在线观看| 超级碰碰碰久久网站| 婷婷情色五月| 任我干视频在线观看| 亚洲国产精品VA在线看黑人| 国产成人精品123区免费视频| 二色AV| 天天摸天天肏| 久久三级视频| 亚洲精品电影| 五月天婷婷久久视频| 玖玖综合色| 成人五月丁香社区| 91热爆在线| www.99久| 日本一级黄色电影| 亚洲精品白浆高清久久久久久| www.色婷婷| 天天做天天爱| 色综合色| 五月天社区| 丁香色色网| 狠狠干综合| 丁香,开心成人,久久| 99精品久| 久草热久草在线视频| www.色五月| 99re思思久久| 另类小说五月天| 一起草av| AA片在线观看视频在线播放| 久草丁香婷婷1024| www.一起草av| 99热费观看| 五月天色色激情综合| 六月丁香婷婷网| 五月丁香色婷婷综合| 99热精品在线免费观看| 狠狠操狠狠插| 天天综合色| 99热主页日本| 婷婷激情图片| 99热9999| 丁香五月婷婷在线| 4399无码视频| 日本久久九| 久久婷婷五月综合网| 大香蕉欧美在线| 99热这里| 99婷婷五月天| 天天日日综合| 综合激情站| 无码色色色| 婷婷综合丁香| 狠狠色五月| 91丨九色丨国产打屁股| 久久AAAA片一区二区| 五月婷性爱| 色婷婷小说| 五月婷久久在线| 欧美人人草| 色综合久久88色综合天天99| 国产精品久久久久久妇女6080| 区欧美日韩成人| 色婷婷五月色| 管管補管管紱| 六月激情久久| 色五月激情五月| 99性色| 97亚洲视频在线| 98色花堂98t.R| 99这里只有精品国产| 亚洲综合激| 五月精品| 99超级碰免费视频| 国产精品国产| 亚洲五月婷婷在线| 色情五月婷婷| 中国女人内射6XXXXX| 激情五月综合网最新| 婷婷伊人无码| 久99视频在线观看| 色婷婷色丁香色欲av| 综合激情伊人影视在线| 五月天激情在线视频| 婷婷五月天成人网| 强壮公让我夜夜高潮A片视频| 六月激情网| 久久婷婷五月草视频| 亚洲成人免费电影| 色婷av| 战争与艾拉电影免费观看| 9色视频在线| 五月天大香焦| 五月丁香六月日逼| 激情婷婷五月天| 亚洲成人在线电影网站| 丁香五月1页| 这里只有精品视频免费在线观看| 五月婷婷啪啪啪啪| 高清激情av在线观看| 91黄操| 啪啪操网| 天天综合亚洲综合| 久热9| 九色 在线| 婷婷射图五月天| 九色PORNY9l原创自拍| 婷婷99视频精品| 婷婷色五天| 真实熟女-91九色| 丁香婷婷六月激情综合| 北京熟妇搡BBBB搡BBBB| 婷婷五月电影院| 9久久久久久久久久久| 综合网网欲色| 婷婷五月天手机版视频| 一本色道久久综合狠狠躁小说| 99热综合网| 色五月婷婷小说亚洲中文字幕组 | 久久久久9| 午夜九九电影| 婷婷五月综合网| 1囯产午夜仑鲁鲁| 99热99re6国产在线播放| 国产成人精品一区二三区熟女在线| 欧美色色色色色色色色| 婷婷亚洲欧美丁香五月| 99免费超碰在线| 深爱五月亚洲| 亚洲网站观看视频| 激情综合网,五月| 免费观看全黄做爰的视频 | 丁香六月天AV| 色婷婷狠狠| 精品综合久久久久久五月天| www久|