假設你運營了一個電影網站,你有不少用戶,而且想知道如何推薦給這些用戶他們喜歡的電影。一個辦法是,把每一個用戶做爲一個文檔建立索引,以下所示(movies_liked被設置爲被分詞的字段,而且用於搜索):後端
PUT recs/user/1 { "movies_liked": ["Forrest Gump", "Terminator", "Rambo", "Rocky", "Good Will Hunting"]} PUT recs/user/2 { "movies_liked": ["Forrest Gump", "Terminator", "Rocky IV", "Rocky", "Rocky II", "Predator"]} PUT recs/user/3 { "movies_liked": ["Forrest Gump", "The Thin Red Line", "Good Will Hunting", "Rocky II", "Predator", "Batman"]} PUT recs/user/4 { "movies_liked": ["Forrest Gump", "Something about Mary", "Sixteen Candles"]}
咱們想給喜歡《終結者》的用戶進行推薦。也就說,咱們須要知道喜歡《終結者》這部電影的用戶還喜歡哪些電影。這是很是常見的「購物籃分析」 - 推薦系統的基礎組件。「購物籃分析」來源於分析用戶的購物籃而且統計出用戶感興趣物品間的關係。研究案例代表,一般在雜貨鋪購買尿片的人同時會選擇購買啤酒。深刻洞察此類行爲將有助於提高用戶和商家的價值。本文咱們聚焦在《終結者》並找出對這部電影可能感興趣的潛在用戶。緩存
利用那些存儲了用戶觀影歷史的ElasticSearch文檔,咱們如何找出看過《終結者》的觀衆喜歡什麼呢?馬上能想到的辦法是進行「項」的聚合。項聚合能夠得出當前搜索結果中特定字段所包含的項的數量。在某些應用中項可能會是電影的ID,可是在這個案例中使用「標題」。咱們將搜索「終結者」關鍵詞並聚合結果中的「movies_liked」字段從而得出觀看《終結者》的用戶同時喜歡其餘電影的名稱以及數量。最終結果展現以下:微信
"movies_like_terminator": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [{ "key": "Forrest Gump", "doc_count": 2 }, { "key": "Rocky", "doc_count": 2 }, { "key": "Terminator", "doc_count": 2 }, { "key": "Good Will Hunting", "doc_count": 1 } }
經過上述的用戶記錄,你能夠了解到喜歡《終結者》的用戶中有兩我的同時喜歡《阿甘正傳》,兩我的同時喜歡《洛奇》。此外,若是咱們對你最喜歡的電影重複這樣的操做(搜索《終結者》或者《鐵血戰士》或者《情到深處》等你喜歡的電影),而後你會獲得一些協同過濾:發起一個搜索,找到那些和你喜歡一樣電影的用戶。而後你能夠比較下還未看過的電影和你喜歡的電影同時出現的次數。架構
可是這種簡單計數的方法是否足夠好呢?咱們在其它文章中進行了討論,認爲用簡單統計同時出現的次數的方法實現推薦系統是一種不好的方法。簡單計數法優先考慮的是全局的廣泛關係,而不是有意義的關係。例如在這個例子中,每一個人都喜歡《阿甘正傳》。若是咱們用這種方法作推薦,那麼每一個用戶都被推薦了《阿甘正傳》。咱們把這種問題稱爲「奧普拉讀書俱樂部」問題,這些關係廣泛存在但不是特別有用。併發
這裏更有趣的是關於電影《終結者》的相關計數結果。以《洛奇》爲例。每一個喜歡《洛奇》的用戶都喜歡《終結者》,居然有100%的重合率!換句話說,《洛奇》在有條件時(喜歡看《終結者》)出現的的比率爲100%,在全局中(無條件時)出現的比率僅爲50%(有2人喜歡《洛奇》,共有4人)。從這個結果來看,《洛奇》很是適合推薦給喜歡《終結者》的用戶的。分佈式
要解決簡單計數法帶來的問題,利用顯著項來聚合是一個更好的方法。這種聚合方法度量了咱們所須要的這種在統計學意義上更重要、更有意義的推薦的關係。它的做用不是計算簡單的項的計數,而是計算項在當前結果中相比於在背景語料庫中的統計顯著性。在《購物籃筐分析》一文中,咱們討論了正反兩種評價顯著性的不一樣方法。如今,咱們來探討一下顯著項能幹什麼。
在咱們深刻以前,咱們先把這種方法拿出來看看:微服務
POST recs/user/_search { "query": { "match": { "movies_liked": "Terminator" } }, "aggregations": { "movies_like_terminator": { "significant_terms": { "field": "movies_liked", "min_doc_count": 1 } } } }
上面(與簡單計數法)惟一的的不一樣是咱們用到了significant_term運算。爲了讓這個操做在咱們這個極小規模的數據集上能得到較好的結果,咱們將min_doc_count設爲1(項關聯的文檔數大於等於1)。
事實上,這一查詢解決了以上的問題,咱們能夠發現《阿甘正傳》在推薦中沒有出現,獲得的推薦顯得更合適:高併發
"buckets": [{ "key": "Rocky", "doc_count": 2, "score": 1, "bg_count": 2 }, { "key": "Terminator", "doc_count": 2, "score": 1, "bg_count": 2 }, { "key": "Rambo", "doc_count": 1, "score": 0.5, "bg_count": 1 }, { "key": "Rocky IV", "doc_count": 1, "score": 0.5, "bg_count": 1 }]
到此爲止了嗎?咱們還需繼續研究:須要理解評分方法在你的數據上是如何工做的。你須要可以深刻了解所使用的評分方法才能創建起真正優秀的推薦系統。如何根據顯著項獲得上面的排名?正如咱們在《購物籃分析》一文中所見,不一樣形式的計分方法有它們本身的優缺點。選擇錯誤的方法可能在推薦的質量方面形成嚴重的後果。網站
我不打算剖析文中出現的全部顯著項(有不少項),但咱們仍是要深刻了解這種方法來教本身如何思考這些問題。這種方法被稱爲JLH。評分公式是:spa
(foregroundPercentage / backgroundPercentage) * (foregroundPercentage - backgroundPercentage)
「Foreground」的意思是該項在當前搜索結果中出現的百分比(檢索結果中用戶喜歡咱們的電影名稱百分比)。 例如,《第一滴血》的「Foreground」在《終結者》搜索結果中佔比是100%。 「Background」 是整個集合的全局百分比。例如,《第一滴血》的是50%。
你將如何評價某一個評分體系是否適合你的用例?讓咱們想象幾個場景,考慮不一樣場景下的得分。而後,能夠批判地思考他們在現實的數據中如何展現。咱們繼續使用電影爲例,這些數據都是假設的:分析JLH評分所用的並非Netflix或Movielens網站上的真正數據。
第一個場景,咱們已經討論過的是每一個人都喜歡的電影。在咱們的數據集中,這是《阿甘正傳》。99.999%的用戶喜歡《阿甘正傳》。
事實上,這種很是受歡迎的電影對JLH評分不太好。使用(Foreground / Background),《阿甘正傳》的評分是100 / 99.999,幾乎爲1。一樣,(Foreground - Background)=(100 - 99.999),幾乎爲0。 正如你將看到的,這是一個至關低的JLH評分。
這樣公平嗎?我認爲,在大多數領域裏,一個物品被接近100%的用戶喜歡是少見的。更有可能的是,不多有人對電影具備可衡量的偏好。 例如,或許每一個人都喜歡《阿甘正傳》,但大多數的「喜歡」是評級或點擊(並不實際觀看),不是100%的用戶與《阿甘正傳》有交集。 固然,我喜歡《阿甘正傳》,但上次我看到它大概是10年前。 這是一個被動的偏好。 當我看到它出如今Netflix上時,我不太可能會興奮。
現實中更常見,最流行的電影或節目是有20%的用戶喜歡的東西。那麼JLH的得分如何呢?好比《心靈捕手》,若是這組用戶中的100%都喜歡,那麼最高得分將是(100/20)(100-20)= 5 80 = 400。比《阿甘正傳》要高不少。
大多數影片會顯示喜歡此影片用戶的百分比。讓咱們來看一個平均電影:《洛奇IV》,有4%的用戶喜歡。
《洛奇IV》使用JLH評分公平嗎?若是「Foreground」的用戶中100%喜歡《洛奇IV》,咱們獲得(100/4)(100 - 4)或25 96 = 2400。明顯超過被推薦的《心靈捕手》!
《心靈捕手》很是受歡迎得分400,《洛奇IV》受歡迎程度通常得分2400。彷佛JLH評分方式對於推薦系統來講有些糟糕?讓咱們考慮這些「最佳狀況」場景的可能性。 100%的用戶喜歡一個電影的同時又喜歡另外一個電影合理嗎?喜歡電影的"Foreground"機率偏離「Background」的可能性有多大?
這很大程度上取決於數據中物品偏好的相對分佈。例如,人們能夠說,若是你喜歡《洛奇III》,你極可能會喜歡《洛奇IV》,也許接近100%重疊。
若是你的數據集「Background」和「Foreground」的差距不大,也許這不是一個大事。 例如,讓咱們考慮「Foreground」的值基於以「Background」百分比爲中心的正態分佈的狀況。讓咱們考慮「Background」和「Foreground」之間的恆定變化是大約75%的變化(《洛奇IV》大概是7 +/- 3%; 《心靈捕手》大概20 +/- 15%)。 在這些也許更現實的狀況下,咱們將指望得分:
《洛奇IV》最佳得分:(7/4)*(7-4)= 5.25
《心靈捕手》最佳分數:(35/20)*(35 - 20)= 26.25
第一項(除法)中兩部電影評分接近。另外一項(減法)拉開了兩部電影的差距。
爲何會這樣?做爲JLH的建立者,Mark Harwood指出,這正是JLH設計的目的。JLH反映了許多推薦系統數據集中看到的模式:受歡迎的物品受歡迎程度不會發生太大變化。若是幾乎每一個人都買雞蛋,那麼分析煎蛋商品對雞蛋銷量影響就會很是小,即使如此,咱們仍然想要這些煎蛋廚師一些建議:即便只能輕微增長雞蛋的銷量也很重要。
做者信息
本文系LeapCloud團隊_雲服務研發成員:秦鵬【原創】
現任LeapCloud服務與架構部負責人,負責公司雲平臺、雲應用的後端研發和維護工做。有多年分佈式、高併發場景的實戰經驗;目前在分佈式存儲、緩存、中間件、容器技術、微服務、公有云等領域均有涉獵。畢業於上海交通大學,曾供職於SAP,後投身MaxLeap致力於爲開發者提供快穩定、可靠的雲服務。
微信公衆號:MaxLeap_yidongyanfa
相關文章
飛馳在Mesos的渦輪引擎上
做者往期佳做
微服務實戰:從架構到發佈(一)
微服務實戰:從架構到發佈(二)
從應用到平臺 – 雲服務架構的演進過程
基於PaaS和SaaS研發的商業雲平臺實戰
想要了解APP製做、開發?歡迎加入技術交流QQ羣:480843919