2016-11-11 46 views
0

我正試圖在Neo4j上實現一個基本推薦系統。基本上,我有用戶喜歡的用戶和藝術家。我想詢問「喜歡達米安的用戶,也喜歡這些藝術家」。這很容易與以下:關於Neo4j與Cypher的罕見常見建議

MATCH (n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]->(n2:Artist {artist_name: "damien rice"}) 
RETURN n.artist_name, COUNT(n) AS COUNT 
ORDER BY COUNT DESC 
LIMIT 30 

雖然這種方法是一種真實的,它返回酷玩樂隊,披頭士如下(這是流行的所有人用戶):

n.artist_name  COUNT 
coldplay    6193 
radiohead   5377 
the beatles   3998 
death cab for cutie 3647 
muse     3252 
the killers   3064 
jack johnson   2966 

我傾向於搞清楚不常見的建議。我想要的方法是通過計算(6193/totalNumberOfLikesForColdplay)給coldplay一個分數。例如,如果總共有61930人喜歡酷玩,那麼它的得分爲9163/91630 = 0.1,我想根據此得分對所有藝術家進行排序。

我試過如下:

MATCH (n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]->(n2:Artist {artist_name: "damien rice"}) 
MATCH (n2:Artist {artist_name: "damien rice"})<-[:LIKES]-(p2:Person) 
RETURN n.artist_name, COUNT(n)/COUNT(n2) AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 

但它永遠tooks。我應該輸入什麼樣的查詢以最有效的方式獲得結果?

編輯:我剛剛意識到,我上面試過的查詢不是我想要的。它計算 numberOfPeopleBothLikedColdplay_DamienRice/numberOfPeopleLikedDamienRice numberOfPeopleBothLikedTheBeatles_DamienRice/numberOfPeopleLikedDamienRice

但是我想計算numberOfPeopleBothLikedColdplay_DamienRice/numberOfPeopleLikedColdplay numberOfPeopleBothLikedTheBeatles_DamienRice/numberOfPeopleLikedTheBeatles ...

也許我t可以更新爲

MATCH (n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]->(n2:Artist {artist_name: "damien rice"}) 
MATCH (n2:Artist {artist_name: n.name})<-[:LIKES]-(p2:Person) 
RETURN n.artist_name, COUNT(p)/COUNT(p2) AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 

但現在,它返回我「(無行)」作爲結果。

EDIT2:至於有人建議,我更新了查詢,如下所示:

MATCH (p2:Person)-[:LIKES]->(n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]-> 
    (n2:Artist {artist_name: "damien rice"}) 
RETURN n.artist_name, COUNT(p)/COUNT(p2) AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 

但它仍然一直運行。順便說一下,我有292516位藝術家,359347位人物,17549962位藝術家和人物之間的關係。你可以假設:人只能像:藝術家一次,而且只有:人可以喜歡:藝術家

+0

如果您想計算喜歡的數量,您應該計算喜歡藝術家的「人物」,即使用「COUNT(p)/ COUNT(p2)」。 –

回答

0

我們可以在這裏做一些改進。

這有助於理解爲什麼您的查詢可能需要這麼長時間。回想一下,Neo4j返回數據列的數據行,這是隨着你的查詢進展而建立起來的。第二場比賽之後,正在建立的是由n2組成的行,以及每個喜歡n2的人與每個喜歡n2的人(因爲你的第二場比賽在同一組人身上創造了一個笛卡爾積)與每個其他藝術家被這些人喜歡。這是一個非常低效的查詢(至少在複雜度上至少爲n^2),並且完全可以預期長時間或永不完成的執行時間。

所以讓我們來解決這個問題。

首先,我們可以完全擺脫第二個匹配,計算n2的喜歡數。相反(假設:人只能像:藝術家一次,而且只有:人可以像:藝術家),我們可以直接計算:LIKES關係的數量。通過首先對此進行重新排序,我們還確保此操作僅對單行數據發生一次,而不是對大量行進行復制。然後我們可以運行第一個MATCH。

MATCH (n2:Artist {artist_name: "damien rice"}) 
WITH n2, SIZE((n2)<-[:LIKES]-()) as n2Likes 
MATCH (n:Artist)<-[:LIKES]-()-[:LIKES]->(n2) 
WITH n, toFloat(COUNT(n))/n2Likes AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 
RETURN n.artist_name, SCORE 

編輯解決澄清的要求。此外,更改的查詢使用float值作爲count,所以得到的分數是小數而不是int。

我們可以使用類似的方法獲取每個藝術家喜歡的SIZE()。

MATCH (n:Artist)<-[:LIKES]-()-[:LIKES]->(n2:Artist {artist_name: "damien rice"}) 
WITH n, toFloat(COUNT(n)) as likesBothCnt 
WITH n, likesBothCnt, SIZE(()-[:LIKES]->(n)) as likesArtist 
WITH n, likesBothCnt/likesArtist as SCORE 
ORDER BY SCORE DESC 
LIMIT 30 
RETURN n.artist_name, SCORE 

但是這個查詢肯定比我提出的第一個查詢慢。提高速度的一種方法是提前緩存藝術家節點上每位藝術家的同樣數量的快照,然後在需要實時計算時使用緩存值。不過,您需要弄清楚如何以及何時更新緩存的值。

+0

感謝您的回覆@InverseFalcon,您的查詢速度相當快,但是我只是對問題進行了編輯,您能否看看它? –

+0

根據您的建議和我的編輯,我更新瞭如下查詢: MATCH(p2:Person) - [:LIKES] - >(n:Artist)< - [:LIKES] - (p:Person) - [ :LIKES] - > (N2:藝術家{ARTIST_NAME: 「達明飯」}) RETURN n.artist_name,COUNT(p)/ COUNT(P2)AS SCORE ORDER BY SCORE DESC LIMIT 30 但仍然永遠在運行 –

+0

根據新的要求更新了我的答案。 – InverseFalcon

0

是否有使用兩個單獨的MATCH子句的原因?使用兩個MATCH子句與使用單個子句的語義不同,請參閱關於uniqueness的Cypher文檔中的註釋。在當前情況下,使用兩個MATCH子句允許p2採用與p相同的值。

MATCH 
    (n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]-> 
    (n2:Artist {artist_name: "damien rice"})<-[:LIKES]-(p2:Person) 
RETURN n.artist_name, COUNT(p)/COUNT(p2) AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 

您也可以在相同的MATCH子句中重複該變量,並獲得相同的結果集。例如:

MATCH 
    (n:Artist)<-[:LIKES]-(p:Person)-[:LIKES]->(n2:Artist {artist_name: "damien rice"}), 
    (n2)<-[:LIKES]-(p2:Person) 
RETURN n.artist_name, COUNT(p)/COUNT(p2) AS SCORE 
ORDER BY SCORE DESC 
LIMIT 30 
+0

感謝您的回覆,但我只是對這個問題進行了編輯,您能否看看它? –