Gegeben haben wir das folgende Neo4j Schema (vereinfacht, aber es zeigt den wichtigen Punkt). Es gibt zwei Arten von Knoten NODE
und VERSION
. VERSION
s sind über eine VERSION_OF
Beziehung mit NODE
verbunden. VERSION
Knoten haben zwei Eigenschaften from
und until
, die den Gültigkeitszeitraum angeben - entweder oder beide können NULL
sein (in Neo4j-Begriffen nicht vorhanden), um unbegrenzt zu bezeichnen. NODE
s kann über eine HAS_CHILD
Beziehung verbunden werden. Wiederum haben diese Beziehungen zwei Eigenschaften from
und until
, die den Gültigkeitszeitraum angeben - entweder oder beide können NULL
(in Neo4j-Begriffen nicht vorhanden) sein, um unbegrenzt zu bezeichnen.Neo4j Cypher Abfrage um Knoten zu finden, die nicht zu langsam verbunden sind
EDIT: Die Gültigkeitsdaten auf VERSION
Knoten und HAS_CHILD
Beziehungen unabhängig sind (auch wenn das Beispiel zufällig zeigt sie ausgerichtet sind).
Das Beispiel zeigt zwei NODE
s A und B . A hat zwei VERSION
s AV1 bis 6/30/17 und AV2 ausgehend von 7/1/17 während B hat nur eine Version BV1, die unbegrenzt ist. B ist mit A über eine HAS_CHILD
Beziehung bis 6/30/17 verbunden.
Die Herausforderung besteht jetzt darin, das Diagramm für alle Knoten abzufragen, die kein Kind sind (das sind Stammknoten) zu einem bestimmten Zeitpunkt. In dem obigen Beispiel sollte die Abfrage nur B zurückgeben, wenn das Abfragedatum z. 6/1/17, aber es sollte B und A zurückgeben, wenn das Abfragedatum z.B. 8/1/17 (weil A ist kein Kind von B ab dem 1.7.17 mehr). heute
Die aktuelle Abfrage ist in etwa ähnlich ist, dass man:
MATCH (n1:NODE)
OPTIONAL MATCH (n1)<-[c]-(n2:NODE), (n2)<-[:VERSION_OF]-(nv2:ITEM_VERSION)
WHERE (c.from <= {date} <= c.until)
AND (nv2.from <= {date} <= nv2.until)
WITH n1 WHERE c IS NULL
MATCH (n1)<-[:VERSION_OF]-(nv1:ITEM_VERSION)
WHERE nv1.from <= {date} <= nv1.until
RETURN n1, nv1
ORDER BY toLower(nv1.title) ASC
SKIP 0 LIMIT 15
Diese Abfrage funktioniert relativ fein im Allgemeinen, aber es beginnt langsam wie die Hölle bekommen, wenn sie auf große Datensätze (vergleichbar mit realen Produktions Datensätze) verwendet. Mit 20-30k NODE
s (und etwa der doppelten Anzahl von VERSION
s) dauert die (echte) Abfrage etwa 500-700 ms auf einem kleinen Docker Container unter Mac OS X), was akzeptabel ist. Aber mit 1.5M NODE
s (und etwa die doppelte Anzahl von VERSION
s) die (echte) Abfrage dauert etwas mehr als 1 Minute auf einem Bare-Metal-Server (läuft nichts anderes als Neo4j). Das ist nicht wirklich akzeptabel.
Haben wir eine Option, diese Abfrage zu optimieren? Gibt es bessere Möglichkeiten, die Versionierung von NODE
s (was ich bezweifle, ist das Leistungsproblem hier) oder die Gültigkeit von Beziehungen zu handhaben? Ich weiß, dass Beziehungseigenschaften nicht indiziert werden können, daher könnte es ein besseres Schema für die Handhabung der Gültigkeit dieser Beziehungen geben.
Jede Hilfe oder auch nur der geringste Hinweis wird sehr geschätzt.
EDIT nach answer from Michael Hunger:
Prozentsatz der Wurzelknoten:
Bei dem aktuellen Beispiel Datensatz (1.5M Knoten) die Ergebnismenge enthält etwa 2k Zeilen. Das sind weniger als 1%.
ITEM_VERSION
Knoten in der erstenMATCH
:Wir die
ITEM_VERSION
nv2
mit zuITEM
Knoten die Ergebnismenge zu filtern, die keine andere VerbindungITEM
Knoten am angegebenen Datum. Das bedeutet, dass entweder keine Beziehung existieren muss, die für das angegebene Datum gültig ist, oder dass das verbundene Element keineITEM_VERSION
hat, die für das angegebene Datum gültig ist. Ich versuche, dies zu verdeutlichen:// date 6/1/17 // n1 returned because relationship not valid (nv1 ...)->(n1)-[X_HAS_CHILD ...6/30/17]->(n2)<-(nv2 ...) // n1 not returned because relationship and connected item n2 valid (nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...) // n1 returned because connected item n2 not valid even though relationship is valid (nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...6/30/17)
Keine Verwendung von Beziehungstypen:
Das Problem hierbei ist, dass die Software ein benutzerdefinierte Funktionen Schema und
ITEM
Knoten durch benutzerdefinierte Beziehung Typen verbunden . Da wir nicht mehrere Typen/Labels für eine Beziehung haben können, ist das einzige gemeinsame Merkmal für diese Art von Beziehungen, dass sie alle mitX_
beginnen. Das wurde hier aus dem vereinfachten Beispiel weggelassen. Würde die Suche mit dem Prädikattype(r) STARTS WITH 'X_'
hier helfen?
Gibt es eine Korrelation zwischen einem: VERSION-Knoten von und bis zum Datum und den von und bis Daten in HAS_CHILD-Beziehungen? Wenn sie ausgerichtet sind, ist es möglicherweise besser, die Beziehung zu den relevanten: VERSION-Knoten zu haben. – InverseFalcon
@InverseFalcon Nein. Die "Versionierung" von Beziehungen und Knoten ist unabhängig. Vielleicht ist das Beispiel nicht das beste, um dies zu veranschaulichen, weil die Versionsgültigkeit für ** AV1 ** zufällig dieselbe ist wie für die 'HAS_CHILD'-Beziehung. Dies können jedoch beliebige Daten sein. –
Wenn Sie wissen, welche rel-Typen Sie suchen wollen, können Sie sie explizit auflisten, zB '- [: X_FOO |: X_BAR *] ->' –