2017-07-03 4 views
2

Ohne unnötig zu spezifisch zu werden, sehe ich das folgende Problem mit Cyper in Neo4j 3.2. Sagen wir, wir haben eine Datenbank mit 3 Entitäten: User, Comment, Like.Neo4j 3.2 Cypher niedrige Leistung

Aus welchem ​​Grund auch immer, ich versuche, die folgende Abfrage ausführen: abzuschließen

MATCH (n:USER) WHERE n.name = "name" 
WITH n 
MATCH (o:USER) 
WITH n, o, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o) 
RETURN n, o, number, count(l) 

Die Abfrage dauert nur wenige Minuten. Wenn ich jedoch einfach die "2000" als Nummer Teil entferne, ist es innerhalb von zehn Millisekunden abgeschlossen.

Hat jemand eine Erklärung warum?

EDIT: Oberes Bild, mit "2000" als Nummer Teil; unten, ohne es.

+1

Meine Annahme ist, dass Sie/cypher 32969 neue Strings erstellt. Treffen Sie GC-Pausen in der JVM? Haben Sie dasselbe bei der Verwendung der Nummer 2000? – manonthemat

Antwort

4

Sie werden Ihre Anfrage haben, um aufzuräumen, jetzt sind Sie nicht Indizes verwenden (so die ursprüngliche Übereinstimmung mit dem bestimmten Namen ist langsam), und dann führen Sie eine kartesischer Produkt gegen alle: Benutzerknoten, dann Zeichenketten für jede Zeile erstellen.

Erstellen Sie zuerst einen Index auf: USER (name), damit Sie Ihren Startknoten schnell finden können.

Dann müssen wir den Rest des Spiels aufräumen.

Versuchen etwas ähnliches statt:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o:User) 
RETURN n, o, number, count(l) 

Sie sollten einen ähnlichen Plan mit dieser Abfrage, wie in der Abfrage, ohne die „2000“ sehen. Der Grund dafür ist, dass, obwohl Ihr Plan ein kartesisches Produkt mit Ihrer Übereinstimmung mit o hat, der Planer intelligent genug war zu erkennen, dass es eine zusätzliche Einschränkung für o gab, da es in Ihrem letzten Spiel in dem Muster vorkommen musste , und seine Optimierung für diese Situation lassen Sie vermeiden, ein kartesisches Produkt durchzuführen.

Die Einführung einer neuen Variablen number verhinderte jedoch, dass der Planer erkannte, dass dies im Grunde die gleiche Situation war, so dass der Planer das kartesische Produkt nicht optimierte.

Versuchen Sie zunächst, explizit anzugeben, wie die Abfrage ausgeführt werden soll, und versuchen Sie, kartesische Produkte in Ihren Abfragen zu vermeiden.

In diesem speziellen Fall ist es wichtig, zu erkennen, dass, wenn Sie MATCH (o:User) in der dritten Zeile haben, dass zu erklären ist nicht, dass die Art von o ein: User im späteren Spiel, es stattdessen sagte, dass in den Ergebnissen für jede Zeile Führen Sie bisher ein kartesisches Produkt gegen alle Benutzerknoten aus, und sehen Sie dann für jeden dieser Benutzerknoten an, welche im angegebenen Muster vorhanden sind. Das ist eine Menge unnötiger Arbeit, verglichen mit der einfachen Erweiterung des bereitgestellten Musters und dem Erhalten von allem: Benutzerknoten, die Sie am anderen Ende des Musters finden.

EDIT

Was beide bekommen: LIKE und: zählt DISLIKE Knoten, vielleicht so etwas wie diese versuchen:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(likeDislike)-[:CREATED_BY]->(o:User) 
WITH n, o, number, head(labels(likeDislike)) as type, count(likeDislike) as cnt 
WITH n, o, number, CASE WHEN type = "LIKE" THEN cnt END as likeCount, CASE WHEN type = "DISLIKE" THEN cnt END as dislikeCount 
RETURN n, o, number, sum(likeCount) as likeCount, sum(dislikeCount) as dislikeCount 

Sie immer noch, dass number Variable dort benötigen Unter der Annahme.

+0

danke für deine antwort. Das klärt ein paar Dinge auf. Der Grund für das Schreiben der Abfrage war jedoch, dass Zeile 3 mehr tun würde, als alle anderen Benutzer zu vergleichen. Stellen wir uns für dieses Beispiel vor, dass es auch DISLIKE-Knoten in der Datenbank gibt, obwohl dies ein Design-Flow wäre. Die Abfrage sollte die Anzahl der DISLIKE-Knoten zwischen n und jedem anderen o zählen, dann zählen auch alle LIKE-Knoten zwischen n und jedem anderen o. – user3455402

+2

Das ist immer noch kein guter Grund, hier ein kartesisches Produkt zu erstellen, das Problem würde sich nur verschlimmern, wenn man zwei Arten von Knoten überprüfen müsste. Es gibt keinen Grund, das Muster für jeden einzelnen zu überprüfen: USER. Prüfen Sie stattdessen einfach, welche Benutzer durch das Muster selbst gefunden werden. Für Ihren Anwendungsfall DISLIKE ist es wahrscheinlich einfacher, den Knoten potentially: LIKE oder: DISLIKE nicht zu beschriften, und dann CASE zu verwenden, um eine Zählung für jeden zu erhalten. – InverseFalcon