2017-01-23 2 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]에 대해 쿼리에서 첫 번째 reduce을 사용하여 n = 2×3×2 = 12을 계산합니다. 그런 다음 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]│ 
└────────────────┴─────────┴───────────┴─────────────┘ 

그래서, 당신의 문제에 대한 쿼리는 다음과 같습니다

╒════════════════════════════════════╕ 
│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(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 

이는 다음과 같습니다 분명히, 우리는 또한 perso을 얻고 싶습니다. 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

멋지게 생각한 해결책을 받아들입니다. 예, person, hobbie, list (place)를 나열하고 나머지를 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에서 이와 같이 그룹화 할 수 없습니다. 모든 사람, 취미, 행을 반환하고 그룹화 된 집합을 만들고 Cartesian 제품을 계산하는 Python 스크립트에서이 작업을 수행해야합니다.

문제는 점점 더 많은 취미와 장소가 늘어남에 따라 많은 조합을 얻는 것입니다.