2017-01-23 187 views
1

我想找到一種將組合組合在一起的方法。 假設我們有人類,愛好,地點,城市類型的節點。說有圖有如下關係(合併)Neo4J Cypher獲得組合

CREATE 
    (Joe:Person {name: 'Joe'}), 
    (hike:Hobby {name: 'hike'}), 
    (eat:Hobby {name: 'eat'}), 
    (drink:Hobby {name: 'drink'}), 
    (Mountain:Place {name: 'Mountain'}), 
    (Lake:Place {name: 'Lake'}), 
    (DavesBarGrill:Place {name: 'Daves BarGrill'}), 
    (Diner:Place {name: 'Diner'}), 
    (Lounge:Place {name: 'Lounge'}), 
    (DiveBar:Place {name: 'Dive Bar'}), 
    (Joe)-[:likes]->(hike), 
    (Joe)-[:likes]->(eat), 
    (Joe)-[:likes]->(drink), 
    (hike)-[:canDoAt]->(Mountain), 
    (hike)-[:canDoAt]->(Lake), 
    (eat)-[:canDoAt]->(DavesBarGrill), 
    (eat)-[:canDoAt]->(Diner), 
    (drink)-[:canDoAt]->(Lounge), 
    (drink)-[:canDoAt]->(DiveBar) 

對於計劃做他的每一個愛好,每天一次,有加息和吃喝的場所8個的組合。我希望能夠在查詢中捕捉到這一點。

簡易方法,

MATCH (p:Person)-[:likes]->(h:Hobby)-[:canDoAt]->(pl:Place) 
RETURN p, h, pl 

,充其量能夠按個人和愛好,這將導致相同愛好的行組合在一起。我想要的是不知何故連擊組,即:

//Joe Combo 1// Joe,hike,Mountain 
       Joe,eat,Daves 
       Joe,drink,Lounge 
//Joe Combo 2// Joe,hike,Lake 
       Joe,eat,Daves 
       Joe,drink,Lounge 

有沒有辦法以某種方式分配一個號碼的所有路徑相匹配,然後使用該任務進行排序?

回答

2

這是一個非常好的問題!我還沒有完整的解決方案,但有一些想法:正如Martin Preusse所說,我們希望生成笛卡爾產品。

這是困難的,但是你可以通過大量的黑客攻擊,包括使用的變通辦法,雙減少:

WITH [['a', 'b'], [1, 2, 3], [true, false]] AS hs 
WITH hs, size(hs) AS numberOfHobbys, reduce(acc = 1, h in hs | acc * size(h)) AS numberOfCombinations, extract(h IN hs | length(h)) AS hLengths 
WITH hs, hLengths, numberOfHobbys, range(0, numberOfCombinations-1) AS combinationIndexes 
UNWIND combinationIndexes AS combinationIndex 
WITH 
    combinationIndex, 
    reduce(acc = [], i in range(0, numberOfHobbys-1) | 
    acc + toInt(combinationIndex/(reduce(acc2 = 1, j in range(0, i-1) | acc2 * hLengths[j]))) % hLengths[i] 
) AS indices, 
    reduce(acc = [], i in range(0, numberOfHobbys-1) | 
    acc + reduce(acc2 = 1, j in range(0, i-1) | acc2 * hLengths[j]) 
) AS multipliers, 
    reduce(acc = [], i in range(0, numberOfHobbys-1) | 
    acc + hs[i][ 
     toInt(combinationIndex/(reduce(acc2 = 1, j in range(0, i-1) | acc2 * hLengths[j]))) % hLengths[i] 
    ] 
) AS combinations 
RETURN combinationIndex, indices, multipliers, combinations 

的想法是這樣的:我們乘潛力值的數量,例如對於['a', 'b'], [1, 2, 3], [true, false],我們計算n = 2×3×2 = 12,使用查詢中的第一個reduce。然後,我們從0到n-1進行迭代,並使用公式a×1 + b×2 + c×6爲每個數字分配一行,其中a,b,c指示各自的值,因此全部爲非負整數,並且a < 2,b < 3c < 2

0×1 + 0×2 + 0×6 = 0 
1×1 + 0×2 + 0×6 = 1 
0×1 + 1×2 + 0×6 = 2 
1×1 + 1×2 + 0×6 = 3 
0×1 + 2×2 + 0×6 = 4 
1×1 + 2×2 + 0×6 = 5 
0×1 + 0×2 + 1×6 = 6 
1×1 + 0×2 + 1×6 = 7 
0×1 + 1×2 + 1×6 = 8 
1×1 + 1×2 + 1×6 = 9 
0×1 + 2×2 + 1×6 = 10 
1×1 + 2×2 + 1×6 = 11 

結果是:

╒════════════════╤═════════╤═══════════╤═════════════╕ 
│combinationIndex│indices │multipliers│combinations │ 
╞════════════════╪═════════╪═══════════╪═════════════╡ 
│0    │[0, 0, 0]│[1, 2, 6] │[a, 1, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│1    │[1, 0, 0]│[1, 2, 6] │[b, 1, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│2    │[0, 1, 0]│[1, 2, 6] │[a, 2, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│3    │[1, 1, 0]│[1, 2, 6] │[b, 2, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│4    │[0, 2, 0]│[1, 2, 6] │[a, 3, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│5    │[1, 2, 0]│[1, 2, 6] │[b, 3, true] │ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│6    │[0, 0, 1]│[1, 2, 6] │[a, 1, false]│ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│7    │[1, 0, 1]│[1, 2, 6] │[b, 1, false]│ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│8    │[0, 1, 1]│[1, 2, 6] │[a, 2, false]│ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│9    │[1, 1, 1]│[1, 2, 6] │[b, 2, false]│ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│10    │[0, 2, 1]│[1, 2, 6] │[a, 3, false]│ 
├────────────────┼─────────┼───────────┼─────────────┤ 
│11    │[1, 2, 1]│[1, 2, 6] │[b, 3, false]│ 
└────────────────┴─────────┴───────────┴─────────────┘ 

因此,對於您的問題,查詢可能是這樣的:

MATCH (p:Person)-[:likes]->(h:Hobby)-[:canDoAt]->(pl:Place) 
WITH p, h, collect(pl.name) AS places 
WITH p, collect(places) AS hs 
WITH hs, size(hs) AS numberOfHobbys, reduce(acc = 1, h in hs | acc * size(h)) AS numberOfCombinations, extract(h IN hs | length(h)) AS hLengths 
WITH hs, hLengths, numberOfHobbys, range(0, numberOfCombinations-1) AS combinationIndexes 
UNWIND combinationIndexes AS combinationIndex 
WITH 
    reduce(acc = [], i in range(0, numberOfHobbys-1) | 
    acc + hs[i][ 
     toInt(combinationIndex/(reduce(acc2 = 1, j in range(0, i-1) | acc2 * hLengths[j]))) % hLengths[i] 
    ] 
) AS combinations 
RETURN combinations 

這看起來是這樣的:

╒════════════════════════════════════╕ 
│combinations      │ 
╞════════════════════════════════════╡ 
│[Diner, Lounge, Lake]    │ 
├────────────────────────────────────┤ 
│[Daves BarGrill, Lounge, Lake]  │ 
├────────────────────────────────────┤ 
│[Diner, Dive Bar, Lake]    │ 
├────────────────────────────────────┤ 
│[Daves BarGrill, Dive Bar, Lake] │ 
├────────────────────────────────────┤ 
│[Diner, Lounge, Mountain]   │ 
├────────────────────────────────────┤ 
│[Daves BarGrill, Lounge, Mountain] │ 
├────────────────────────────────────┤ 
│[Diner, Dive Bar, Mountain]   │ 
├────────────────────────────────────┤ 
│[Daves BarGrill, Dive Bar, Mountain]│ 
└────────────────────────────────────┘ 

很顯然,我們也想得到這個人n和他/她的愛好的名字:

MATCH (p:Person)-[:likes]->(h:Hobby)-[:canDoAt]->(pl:Place) 
WITH p, h, collect([h.name, pl.name]) AS places 
WITH p, collect(places) AS hs 
WITH p, hs, size(hs) AS numberOfHobbys, reduce(acc = 1, h in hs | acc * size(h)) AS numberOfCombinations, extract(h IN hs | length(h)) AS hLengths 
WITH p, hs, hLengths, numberOfHobbys, range(0, numberOfCombinations-1) AS combinationIndexes 
UNWIND combinationIndexes AS combinationIndex 
WITH 
    p, reduce(acc = [], i in range(0, numberOfHobbys-1) | 
    acc + [hs[i][ 
     toInt(combinationIndex/(reduce(acc2 = 1, j in range(0, i-1) | acc2 * hLengths[j]))) % hLengths[i] 
    ]] 
) AS combinations 
RETURN p, combinations 

結果:

╒═══════════╤════════════════════════════════════════════════════════════╕ 
│p   │combinations            │ 
╞═══════════╪════════════════════════════════════════════════════════════╡ 
│{name: Joe}│[[eat, Diner], [drink, Lounge], [hike, Lake]]    │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Daves BarGrill], [drink, Lounge], [hike, Lake]]  │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Diner], [drink, Dive Bar], [hike, Lake]]    │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Daves BarGrill], [drink, Dive Bar], [hike, Lake]] │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Diner], [drink, Lounge], [hike, Mountain]]   │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Daves BarGrill], [drink, Lounge], [hike, Mountain]] │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Diner], [drink, Dive Bar], [hike, Mountain]]   │ 
├───────────┼────────────────────────────────────────────────────────────┤ 
│{name: Joe}│[[eat, Daves BarGrill], [drink, Dive Bar], [hike, Mountain]]│ 
└───────────┴────────────────────────────────────────────────────────────┘ 

我可能是這個得太多,所以任何意見是值得歡迎的。

一個重要的評論:這與純Cypher如此複雜的事實可能是一個很好的跡象,你最好從客戶端應用程序計算。

+0

接受爲出色想出解決方案!是的,編寫一個簡單的查詢可能會更有意義,該查詢列出了人員,hobby,列表(地點),並在cilent應用程序中執行其他操作。 – Azeli

+0

您正在反思這一點,但它仍然非常令人印象深刻;) –

1

我很確定你不能在密碼中這樣做。你在尋找的是所有按人物和愛好分組的地方的笛卡爾積。

A: [ [Joe, hike, Mountain], [Joe, hike, Lake] ] 
B: [ [Joe, eat, Daves], [Joe, eat, Diner] ] 
C: [ [Joe, drink, Lounge], [Joe, drink, Bar] ] 

而你正在尋找A x B x C

據我所知,你不能像這樣在Cypher中歸隊。您應該返回所有人,業餘愛好,放置行,並在Python腳本中執行此操作,在該腳本中構建分組集並計算笛卡爾積。

問題是,你會得到很多與業餘愛好和場所數量的組合。