我正在尝试找到一种将组合分组在一起的方法。 假设我们有类型人,爱好,地方,城市的节点。假设图表具有以下关系(合并)
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
有没有办法以某种方式为所有路径匹配分配一个数字,然后使用该分配进行排序?
答案 0 :(得分: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索引相应的值,因此所有都是非负整数和{{1} },a < 2
和b < 3
。
c < 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]│
└────────────────────────────────────┘
结果:
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
我可能会过度思考这个问题,所以欢迎提出任何意见。
一个重要的评论:纯粹Cypher这么复杂的事实可能是一个好的迹象,表明您最好不要从客户端应用程序计算它。
答案 1 :(得分: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脚本中执行此操作,您将在其中构建分组集并计算笛卡尔积。
问题是你会在越来越多的爱好和场所中获得很多组合。