2016-04-27 5 views
2

Ich renne in diese Wand in Bezug auf bidirektionale Beziehungen.Wie kann ich bidirektionale Beziehungen in einem Familienstammbaum in Neo4j mindern?

Angenommen, ich versuche ein Diagramm zu erstellen, das einen Familienstammbaum darstellt. Das Problem ist hier:
* Timmy kann Suzies Bruder sein, aber
* Suzie kann nicht Timmys Bruder sein.

Somit wird es notwendig, diese in zwei Richtungen zu modellieren:

enter image description here

(Sicher, technisch konnte ich SIBLING_TO sagen und nur eine Kante verlassen ... was ich bin mir nicht sicher, was das Vokabular ist, wenn ich versuche, eine Oma mit einem Enkel zu verbinden.)

Wenn alles gesagt und getan ist, bin ich ziemlich sicher, es gibt keinen Weg um die Tatsache, dass die Richtung in diesem Beispiel zählt.

Ich las diese blog post, in Bezug auf gemeinsame Neo4j Fehler. Der Autor stellt fest, dass diese Bidirektionalität nicht der effizienteste Weg zum Modellieren von Daten in Neo4j ist und vermieden werden sollte.

Und ich fange an zuzustimmen. Ich habe ein Mock Set mit 2 Familien eingerichtet:
enter image description here und ich fand, dass viele Abfragen, die ich ausführen wollte, sehr, sehr langsam verliefen. Dies liegt an der "Alles verbunden mit allen" Natur des Graphen, zumindest innerhalb der jeweiligen Familie.

Meine Frage ist diese:
1) Bin ich richtig zu sagen, dass Bidirektionalität nicht ideal ist?

2) Wenn ja, ist mein Beispiel eines Familienstammbaums auf andere Weise darstellbar ... und was ist die 'Best Practice' in den vielen Situationen, in denen mein Problem auftreten kann?

3) Wenn es nicht möglich ist, den Familienstammbaum auf eine andere Art und Weise darzustellen, ist es technisch möglich, auf eine Art und Weise Abfragen zu schreiben, die das Problem von 1) umgehen?

Vielen Dank für das Lesen und für Ihre Gedanken.

+0

bidirektionale Verbindungen von der gleichen Kante Namen sind redundant und fügen Sie nicht Wert . Bruder und Schwester - um Informationen zu vermitteln, obwohl das aus einer Immobilie abgeleitet werden könnte. Eine (Kind) - [: PARENT] -> (Eltern) -Beziehung bringt Ihnen die Eltern-Kind-Beziehung und bringt Ihnen die gesamte biologische Familienbeziehung, und Sie können sie für jede Generation von Eltern/Kindern verwenden. Stiefkinder wären eine andere Sache. –

Antwort

1

Das Speichern von redundanten Informationen (Ihre bidirektionalen Beziehungen) in einer DB ist nie eine gute Idee. Hier ist eine bessere Möglichkeit, einen Stammbaum darzustellen.

Um "Geschwisterlichkeit" anzugeben, benötigen Sie nur einen einzigen Beziehungstyp, sagen Sie SIBLING_OF, und Sie müssen nur eine einzige solche Beziehung zwischen 2 Geschwisterknoten haben.

Um Vorfahren anzugeben, brauchen Sie nur einen einzigen Beziehungstyp, sagen Sie CHILD_OF, und Sie müssen nur eine einzelne solche Beziehung zwischen einem Kind zu jedem seiner Eltern haben.

Sie sollten auch eine Knotenbezeichnung für jede Person haben, sagen Sie Person. Und jede Person sollte eine eindeutige ID-Eigenschaft (z. B. id) und eine Art von Eigenschaft haben, die auf Geschlecht verweist (z. B. eine boolesche isMale).

Mit diesem sehr einfachen Datenmodell, hier sind einige Beispielabfragen:

  1. Zur Person 123 Schwestern finden (beachten Sie, dass das Muster nicht angibt, eine Beziehung Richtung):

    MATCH (p:Person {id: 123})-[:SIBLING_OF]-(sister:Person {isMale: false}) 
    RETURN sister; 
    
  2. Um die Großväter von Person 123 zu finden (beachten Sie, dass dieses Muster angibt, dass übereinstimmende Pfade eine Tiefe von 2 haben müssen):

    MATCH (p:Person {id: 123})-[:CHILD_OF*2..2]->(gf:Person {isMale: true}) 
    RETURN gf; 
    
  3. Zur Person 123 Urenkel zu finden:

    MATCH (p:Person {id: 123})<-[:CHILD_OF*3..3]-(ggc:Person) 
    RETURN ggc; 
    
  4. Zur Person 123 der Onkel mütterlicherseits zu finden:

    MATCH (p:Person {id: 123})-[:CHILD_OF]->(:Person {isMale: false})-[:SIBLING_OF]-(maternalUncle:Person {isMale: true}) 
    RETURN maternalUncle; 
    
+0

Diese Antwort war genau das, was ich hören musste - vielen Dank. Obwohl die Idee hinter Direktionalität in meinem Kopf immer noch skizzenhaft ist (warum Richtung anwenden, wenn sie irrelevant ist oder nicht?), Ist die Idee, Redundanz zu reduzieren, so dass Sie die minimale Anzahl von Beziehungen haben, absolut golden. Die Beispielabfragen sind fantastisch. Danke noch einmal. –

0

Ich bin mir nicht sicher, ob Sie wissen, dass es möglich ist, bidirektional abzufragen (dh die Richtung zu ignorieren). So können Sie tun:

MATCH (a)-[:SIBLING_OF]-(b) 

und da ich nicht mit einer Richtung übereinstimmen wird es beide Wege übereinstimmen. So würde ich vorschlagen, Dinge zu modellieren.

Im Allgemeinen möchten Sie nur mehrere Beziehungen erstellen, wenn Sie tatsächlich einen anderen Status speichern möchten. Zum Beispiel könnte eine KNOWS Beziehung nur auf eine Weise gelten, weil Person A Person B kennen könnte, B aber möglicherweise nicht A. Sie haben möglicherweise eine LIKES Beziehung mit einer Werteigenschaft, die angibt, wie viel A wie B ist, und möglicherweise unterschiedliche Stärken von "liking" in den beiden Richtungen

+0

Würdest du zustimmen, dass "Enkelin" und "Großmutter von" unterschiedliche Zustände sind und somit multiple Beziehungen erfordern? –

+0

Ich glaube nicht ... Ich würde sagen, dass diese beiden Beziehungen verschiedene Möglichkeiten darstellen, den gleichen Sachverhalt in Ihrer Datenbank darzustellen. Dies ist ein Aspekt der Modellierung in Neo4j. Sie müssen einen auswählen und dabei bleiben –

+0

Besser noch, wenn es für Sie Sinn macht, ist Großeltern zu finden, indem Sie einen Pfad von zwei child_of Beziehungen abgleichen. Aber Sie haben das nicht immer und Sie wollen immer noch die Enkelkind-Beziehung darstellen. –

Verwandte Themen