2017-01-04 2 views
0

Ich habe einen Knoten für jeden von 25 Seminaren und einen Knoten für jeden der 70 Clients erstellt.Suche nach Top-n "Freunden" mit gemeinsamen Interesse

Seminare kommen mehrmals im Monat in keiner bestimmten Reihenfolge, und jedes Seminar findet nur 5 Clients zu einem Zeitpunkt, und könnte jede 5 der 70. zur Zeit jedes Auftreten eines Seminars als auch am erfassen als die besucht:

MATCH (c1:Client {id: cid}), ..., (c5:Client {id: cid}), (s:Seminar {id: sid}) 
WITH c1, c2, c3, c4, c5 
CREATE UNIQUE (c1)-[:ATTENDED {event_id: eid}]->(s) 
... 
CREATE UNIQUE (c5)-[:ATTENDED {event_id: eid}]->(s) 
WITH c1, c2, c3, c4, c5, s 
MERGE (c1)-[x:WITH]-(c2) 
ON MATCH SET x.count = x.count + 1 
ON CREATE SET x.count = 1 
...repeat for c1 & c3, c1 & c4, c1 & c5 
WITH c2, c3, c4, c5 
...repeat c2 & c3, c2 & c4, c2 & c5 
WITH c3, c4, c5 
...repeat for c3 & c4, c3 & c5... 
WITH c4, c5 
MERGE (c4)-[x:WITH]-(c5) 
ON MATCH SET x.count = x.count + 1 
ON CREATE SET x.count = 1; 

Für eine neue Veranstaltung:

(x:Seminar {event_id: xid}) 

Ich mag würde das Top-5-Clients "Ziel", das verschiedene Seminare, so dass

(:Client)-[r:WITH]-(:Client) WHERE r.count >= 1 
012 teilgenommen hat

Ziel ist es, Kunden zu gewinnen, die "am meisten vertraut" sind. Wie codiere ich diese Abfrage? Habe ich genug Informationen (Beziehungen und Eigenschaften)? Gibt es eine bessere Möglichkeit, die Ereignisdaten hinzuzufügen?

Antwort

1

Ich kann eine Alternative zum Aufbau Ihrer: WITH Beziehungen vorschlagen.

MATCH (c:Client)-[:ATTENDED]->(:Seminar)<-[:ATTENDED]-(co:Client) 
WITH c, co, COUNT(co) as timesWith 
MERGE (c)-[r:WITH]-(co) 
SET r.count = timesWith 

Diese Sie für jeden Kunden eine Reihe bekommt, einen Client sie Seminare besucht mit, und die Anzahl der Zeiten, die sie mit ihnen ein Seminar besucht, und speichert (oder Updates), die auf Ihrem zählen: MIT Beziehungen.

Sie können Ihre Abfrage für das Erstellen von Seminaren und die Beziehungen zwischen Clients und Seminaren viel einfacher machen, wenn Sie eine Sammlung von IDs als Parameter für Ihre Abfrage bereitstellen können, da Sie dies auf einmal statt einzeln tun können:

MATCH (c:Client), (s:Seminar {id: sid}) 
WHERE c.id IN {attendeeIDs} 
MERGE (c)-[:ATTENDED]->(s) 
// and then you can run the query above to update WITH relationships if necessary 

Wie für den Rest von dem, was Sie wollen, ist das eine ziemlich knifflige Abfrage, und ich bin nicht sicher, ob Sie es klar gemacht haben, was sollte Ihr Ansatz.

Suchen Sie eine Reihe von 5: Clients wie die Summe der Zählungen der: WITH Beziehungen zwischen ihnen ist die größte von jeder anderen Gruppe von 5? Weil diese Art von Abfrage erfordert, dass Sie jede Kombination von 5 Clients testen und diese Berechnung durchführen müssen, und wir müssen auch besonders darauf achten, dass wir dies mit Kombinationen und nicht mit Permutationen tun.

Auch dann wird es sehr teuer Abfrage, da die Anzahl der Kombinationen von Sätzen von 5 von 70 Möglichkeiten ist C (70,5) = 12.103.014. Das ist eine Menge aufgebauter Zeilen und Operationen, die auf jeder einzelnen dieser Zeilen ausgeführt werden.

// first match on a combination of 5; id inequalities prevent permutations 
MATCH (c1:Client), (c2:Client), (c3:Client), (c4:Client), (c5:Client) 
WHERE id(c1) < id(c2) < id(c3) < id(c4) < id(c5) 
WITH c1, c2, c3, c4, c5, [id(c1),id(c2),id(c3),id(c4),id(c5)] as ids 
// find all possible :WITH relationships between each set of 5 
OPTIONAL MATCH (a)-[r:WITH]-(b) 
WHERE id(a) in ids AND id(b) in ids 
WITH c1,c2,c3,c4,c5, SUM(r.count) as togetherness 
ORDER BY togetherness DESC 
RETURN c1,c2,c3,c4,c5 
LIMIT 1 

Es gibt Möglichkeiten, dies effizienter zu machen. Anstatt alle zu betrachten: Kunden, könnten Sie zuerst versuchen, das Top-n oder so zu bekommen: Clients basierend auf Seminaren besucht, und dann versuchen, eine ähnliche Abfrage auszuführen.

Dies ist, wie es aussehen könnte, wenn Sie den Top-15-Teilnehmer bis zum Seminar Teilnahme zuerst ausgewählt, dann versucht, die Gruppe von 5 zu finden, das gemeinsam von denen waren das Beste aus 15:

MATCH (c:Client) 
WITH c, SIZE((c)-[:ATTENDED]->(:Seminar)) as attendance 
ORDER BY attendance DESC 
WITH c 
LIMIT 15 
WITH COLLECT(id(c)) as ids 
// first match on a combination of 5; id inequalities prevent permutations 
MATCH (c1:Client), (c2:Client), (c3:Client), (c4:Client), (c5:Client) 
WHERE id(c1) in ids, id(c2) in ids, id(c3) in ids, id(c4) in ids, id(c5) in ids 
AND id(c1) < id(c2) < id(c3) < id(c4) < id(c5) 
WITH c1, c2, c3, c4, c5, [id(c1),id(c2),id(c3),id(c4),id(c5)] as ids 
// find all possible :WITH relationships between each set of 5 
OPTIONAL MATCH (a)-[r:WITH]-(b) 
WHERE id(a) in ids AND id(b) in ids 
WITH c1,c2,c3,c4,c5, SUM(r.count) as togetherness 
ORDER BY togetherness DESC 
RETURN c1,c2,c3,c4,c5 
LIMIT 1