天天看點

如何輕松實作個性化推薦系統以圖書商城為例 MVC

這裡采用的是.net的一個引用NReco.Recommender.dll,這是一個國外電影網站推薦系統衍生而來的,有興趣的可以到他們的官網看看。

以圖書商城為例 MVC

構造行為資料

首先需要對資料庫進行設計,增加一張使用者的行為資料表,記錄使用者通路網站的行為,例如商城的一般記錄浏覽的商品和購買過的商品,根據你的業務邏輯進行設計。

構造評分資料

需要對商品的進行評分,一般采用5分制,可以根據你的業務邏輯進行設計。

生成評分離線資料

public class IndexJobRatings : IJob
    {
        Irecommend_ratingBLL ratingbll = new BLL.recommend_ratingBLL();
        ISettingsBLL setingsbll = new BLL.SettingsBLL();
        #region IJob 成員
        /// <summary>
        /// 定時處理任務都要放在這個方法
        /// </summary>
        /// <param name="context"></param>
        public void Execute(JobExecutionContext context)
        {
            var list = ratingbll.LoadEntities(c => true).ToList();
            StringBuilder sb = new StringBuilder();
            foreach (var item in list)
            {
                //需要過濾 取平均值
                sb.Append(item.userID   "\t"   item.bookID   "\t"   item.stars   "\t"   WebCommon.DateTimeToUnixTimestamp(Convert.ToDateTime(item.addTime))   "\r\n");
            }
            var logmodel = setingsbll.LoadEntities(c=>c.id==16).FirstOrDefault();
            if (logmodel != null && logmodel.value == "true")
            {
                System.IO.File.WriteAllText(WebCommon.MapPath("/data/ratings.dat"), sb.ToString());//寫入檔案  
                logmodel.value = "false";
                setingsbll.UpdateEntity(logmodel);
            }
            else
            {
                System.IO.File.WriteAllText(WebCommon.MapPath("/data/ratings1.dat"), sb.ToString());//寫入檔案
                logmodel.value = "true";
                setingsbll.UpdateEntity(logmodel);
            }
        }

        #endregion
    }           
本人使用時間進度插件定時執行改任務,更新資料提高資料的準确率。

添加引用

直接在NuGet管理中添加即可,搜尋NReco.Recommender

實作推薦

/// <summary>
        /// 推薦
        /// </summary>
        /// <param name="pageIndex">目前頁</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="showCount">顯示數量</param>
        /// <returns></returns>
        public List<Books> RecommendBooks(int pageIndex, int pageSize, int showCount)
        {
            #region 推薦
            List<Books> books = null;
            if (Session["user"] != null)
            {
                Users user = Session["user"] as Users;

                #region 建構使用者行為數組
                var loglist = logbll.LoadEntities(c => c.userID == user.Id).ToList();
                StringBuilder sb = new StringBuilder();
                if (loglist.Count > 0)
                {
                    sb.Append("[");
                    int j = 0;
                    foreach (var item in loglist)
                    {
                        j  ;
                        sb.Append(item.itemID.ToString());
                        if (j != loglist.Count)
                        {
                            sb.Append(",");
                        }
                    }
                    sb.Append("]");
                }
                #endregion

                if (string.IsNullOrEmpty(sb.ToString()))
                {
                    //冷啟動
                    books = booksbll.LoadEntities(c => true).OrderByDescending(c => c.rating).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                }
                else
                {
                    var filmIds = (new JavaScriptSerializer()).Deserialize<long[]>(sb.ToString());

                    var logmodel = settingbll.LoadEntities(c => c.id == 16).FirstOrDefault();
                    string path = "";
                    if (logmodel != null && logmodel.value == "true")
                    {
                        path = "data/ratings1.dat";
                    }
                    else
                    {
                        path = "data/ratings.dat";
                    }

                    var pathToDataFile =
                            Path.Combine(System.Web.HttpRuntime.AppDomainAppPath, path);

                    if (dataModel == null)
                    {
                        dataModel = new FileDataModel(pathToDataFile, false, FileDataModel.DEFAULT_MIN_RELOAD_INTERVAL_MS, false);
                    }

                    var plusAnonymModel = new PlusAnonymousUserDataModel(dataModel);
                    var prefArr = new GenericUserPreferenceArray(filmIds.Length);
                    prefArr.SetUserID(0, PlusAnonymousUserDataModel.TEMP_USER_ID);
                    for (int i = 0; i < filmIds.Length; i  )
                    {
                        prefArr.SetItemID(i, filmIds[i]);
                        prefArr.SetValue(i, 5); // lets assume max rating
                    }
                    plusAnonymModel.SetTempPrefs(prefArr);

                    var similarity = new LogLikelihoodSimilarity(plusAnonymModel);
                    var neighborhood = new NearestNUserNeighborhood(15, similarity, plusAnonymModel);
                    var recommender = new GenericUserBasedRecommender(plusAnonymModel, neighborhood, similarity);
                    var recommendedItems = recommender.Recommend(PlusAnonymousUserDataModel.TEMP_USER_ID, showCount, null);
                    List<Books> newbooks = new List<Books>();
                    foreach (var item in recommendedItems)
                    {
                        int bid = Convert.ToInt32(item.GetItemID());
                        newbooks.Add(booksbll.LoadEntities(c => c.Id == bid).FirstOrDefault());
                    }

                    books = newbooks.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                }
            }
            else //不推薦
            {
                books = booksbll.LoadEntities(c => true).OrderByDescending(c => c.rating).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            #endregion

            return books.Count() <= 0 ? booksbll.LoadEntities(c => true).OrderByDescending(c => c.rating).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList() : books;
        }           
當然直接這樣會有冷啟動問題,就是使用者沒有登入的情況和使用者還沒有行為資料的情況,本人采用熱門商品的推薦。你也可以根據你的業務邏輯進行設計。
這隻是本人的簡單實作方案,還需要不斷的完善,歡迎提出意見或建議,感謝您的閱讀。