2017-01-23 183 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脚本中执行此操作,在该脚本中构建分组集并计算笛卡尔积。

问题是,你会得到很多与业余爱好和场所数量的组合。