Neo4J Data Model - neo4j

I'm new to Neo4J and I have a question about the most appropriate data model for a the problem domain described below.
Background
As I understand it, in Neo4J every relationship has a direction of sorts, outgoing, incoming or undirected. I read that a common mistake newbies make in "bi-directional" relationships is that they might model the relationship in both directions where in reality one undirected relationship would serve the purpose well. I also understand that irrespective of the direction it is possible at query time to ignore it and query based on either side of the relationship.
Problem Domain
This is a bit cliché, but stick with me, in a graph where "People" can connect with one another I felt tempted to model that as an undirected relationship. However, perhaps in my problem domain I want to store meta data on the relationship edge rather than at either of the People nodes. E.g. timestamp of when then connected or type of relationship (friend, family, employer etc...). Perhaps this is a "side effect" of using the spring-data-neo4j libraries but it seems that if I wish to data meta data on the edge rather than at the node I must create a class which is annotated as #RelationshipEntity rather than #NodeEntity. This necessitates a #StartNode and #EndNode which then seems to imply a direction to my otherwise undirected relationship...
Now, as it turns out this might not be a bad thing in my case because perhaps after all it turns out there is something useful about this additional directed context (e.g. perhaps I want to know who initiated the relationship so that the target node (person) must accept the invitation to be friends).
Now imagine that each person can place the "relationship" into a "group" like "friends, family, colleagues" etc I feel like I'd now need to actually have two distinct edges that point in either direction so that the meta data specific to the given direction has a natural place to reside. But this seems to have been described as a newbie anti-pattern.
Questions
I have two questions:
1) Should I use two separate distinct relationship edges that essentially point either way as a bi-directional relationship if I need to store meta data that is specific to the direction. e.g. Person A <--> Person B but person A placed Person B in the friends group whereas Person B placed A in the colleagues group.
2) Given the Java data model below, I am unclear what the direction attribute on the #Relationship annotation of Person should be. If I specify nothing it default to OUTGOING. But since it's a reflective relationship depending on which person instance you look at the relationship could be either outgoing or incoming, e.g. if person A adds person B, both are Person instances, but the direction is outgoing on the person A instance and incoming on the person B instance. Should the annotation be omitted altogether since I'm using a #RelationshipEntity?
Java Data Model
#NodeEntity
#EqualsAndHashCode(of = {"id"})
#NoArgsConstructor
public abstract class Person {
#GraphId
private Long id;
... other attributes
#Relationship(type = "CONNECTION_OF", direction = UNDIRECTED)
private Set<Connection> connections;
}
#Data
#RelationshipEntity(type = "CONNECTION_OF")
public class Connection {
#GraphId
private Long relationshipId;
... other meta-data
#StartNode
private Person from;
#EndNode
private Person to;
}

1) The rule of thumb that works well is to answer a question - if a relationship from A to B exists, can another relationship from B to A still be created, with different metadata? And can you delete one direction of the relationship independently of the other?
If the answer is yes they go for two directed relationships, otherwise stay with UNDIRECTED, and create initiatedBy=userId property or similar.
For your case where you put connections into groups - the thing is that you really categorize the people from another person's view, maybe it is a completely different fact independent of the CONNECTED_TO relationship?
You could e.g. create a group node and link that to owner and all people in the group, with following schema:
(:Person)-[:OWNS]-(:Group)-[:CATEGORIZED]-(:Person)
2) Keep the #Relationship(type = "CONNECTION_OF", direction = UNDIRECTED). For a given person X the connections Set is going to have elements that have from=X for outgoing edges mixed with elements that have to=X for incoming. All of these will be mixed in one collection.

Related

Neo4j data modeling POJO for relationships

I am using Spring Data with Neo4j, and I am creating POJOs for my schema. In this schema I have a node called Person, with the usual attributes, name, lastname, etc... I also have a relationship called DRIVES which establishes a relationship with another node called carModel:
(person)-[:DRIVES]->(carModel).
In my Person class, I have defined all the property fields and an annotation for the relationship and method as following:
#Relationship(type = "DRIVES", direction = Relationship.UNDIRECTED)
public CarModel carModel;
My question is, if in the CarModel class do I need to define the relationship as well ?
It is completely fine to create a model which declares the relationship only on one side.
The reasons for it might be
you simply don't want to refer from your CarModel class to Person
saves time during save operation on CarModel - SDN does not need to check if related Person has changed
UPDATE
The relationships stored in Neo4j are traversable in both directions, despite being defined only in Person class.
Using custom cypher queries you can query Person by CarModel and also CarModel by Person.
When using derived finders in SDN you can only use the direction which is defined in your class model.

Graph Database Data Model of One Type of Object

Say I'm a mechanic who's worked on many different cars and would like to keep a database of the cars I've worked on. These cars have different manufacturers, models, and some customers have modified versions of these cars with different parts so it's not guaranteed the same model gives you the same car. In addition, I would like to see all these different cars and their similarities/differences easily. Basically the database needs to both represent the logical similarities/differences between all cars that I encounter while still giving me the ability to push/pull each instance of a car I've encountered.
Is this more set up for a relational or graph database?
If a graph database, how would you go about designing it? Each of the relationship labels would just be a 'has_a' or 'is_a_type_of'. Would you have the logical structure amongst all the cars and for each individual car have them point to the leaf nodes? Or would you have each relationship represent each specific car and have those relationships span the logical tree structure of the cars?
Alright so a "graphy" way to go about this would be to create a node type for each kind of domain object. You have a Car identified by a VIN, it can be linked to a Make, Model, and Year. You also have Mechanic nodes that [:work_on] various Car nodes. Don't store make/model/year with the Car, but rather link via relationships, e.g.:
CREATE (c:Car { VIN: "ABC"})-[:make]->(m:Make {label:"Toyota"});
...and so on.
Each of the relationship labels would just be a 'has_a' or
'is_a_type_of'.
Probably no, I'd create different relationship types unique to pairings of node types. So Mechanic -> Car would be :works_on, Car -> Model would be [:model] and so on. I don't recommend using the same relationship type like has_a everywhere, because from a modeling perspective it's harder to sort out the valid domain and ranges of those relationships (e.g. you'll end up in a situation where has_a can go from just about anything to just about anything, and picking out which has_a relationships you want will be hard).
Or would you have each relationship represent each specific car and
have those relationships span the logical tree structure of the cars?
Each car is its own node, identified by something like a VIN, not by a make/model/year. (Splitting out make/model/year later will allow you to very easily query for all Volvos, etc).
Your last question (and the toughest one):
Is this more set up for a relational or graph database?
This is an opinionated question (it attracts opinionated answers), let me put it to you this way: any data under the sun can be done both relationally and via graphs. So I could answer both yes relational, and yes graph. Your data and your domain doesn't select whether you should do RDBMS or Graph. Your queries and access patterns select RDBMS vs. graph. If you know how you need to use your data, which queries you'll run, and what you're trying to do, then with that information in hand, you can do your own analysis and determine which one is better. Both have strengths and weaknesses and many points of tradeoff. Without knowing how you'll access the data, it's impossible to answer this question in a really fair way.

How to fetch records from a class which has parent class reference?

I'm new to CoreData structure, I have two classes one is "Person.h" and another is "Education.h" which has one to many relations ship Person<--->> Education`.
Here's the attributes for each classes,
Person.h
personID (unique) Number
pName String
pAge Number
educations Set
here, p stands for person
Education.h
educationID (unique) Number
eName String
eState Number
eStarted String
eCompleted String
eCenterName String
eBy Person
here, e stands for education
Ok, now I want to fetch (all / some) education details for a Person. I've successfully inserted records in both the classes with proper inputs. How to get this done? Any suggestion? Please consider me to correcting, even if this flow would not clear to you (or its wrong).
Thanks,
Hagile
Normally you'd have a Core Data relationship on Person that points to the Education entity, configured as to-many. Then once you have an instance of Person, you just look up the value of that relationship like you'd look up the value of any property. You get back a collection of zero or more related Education instances, and you don't need to do an additional fetch.
Your eBy relationship on Education suggests that you're thinking of this as if you were working with SQL. With Core Data it's normal to have a to-many relationship defined on the entity that has the relationship (and indeed, eBy should really have an inverse relationship).

Neo: Class name of Node?

This question may seem a little bit naive, but do nodes have class names? I'm new to Neo4j and I've been looking at examples of how it is implemented in web frameworks, Rails especially. It seems like each node obviously holds the values of the class it belongs to, but, unless I'm misinformed, they don't seem to have class/table names like MySQL would have (eg table 'users'). If this isn't true, then why am I seeing so many examples of instantiated nodes with just the class fields and not the actual class name? If this is true, how would I refer to all nodes of a certain class (or create them)? Through their edges?
Check out Neo4J Labels. A label is a way of, well, labeling a node in neo4j according to a certain class it might belong to. So you might create a node with the label "Person". This isn't exactly what you mean by a "class" but a lot of people use it in roughly the same way.
By labeling nodes with class names that are relevant for your domain, you get the ability to query all of them, and only those nodes of a certain "class". Example:
MATCH (user:Person)-[:FRIEND]-(friend:Person) RETURN user, friend
This query specifies that "user" and "friend" must both be labeled "Person", which I think is pretty close to what you want.

Do I need to assign a Grails hasOne relationship in both directions?

Must I assign the relationship in each direction? Using the textbook domain classes for the hasOne relationship, this appears necessary from my testing so far to get the instances to recognize each other:
def face = new Face()
def nose = new Nose()
face.nose = nose
nose.face = face
I don't know why, though. And it's unconventionally awkward. I'm expecting there's a better way.
EDIT:
I need help with the relationship assignment. I do not need information on the mechanics of setting up a hasOne relationship in the domain classes, or a discussion about the wisdom of bi-directional references. I want to know why it takes more than a single statement to set the relationship between a nose instance and a face instance.
My two-statement solution is based on trouble I'm having in a complex application. I am going to try to reproduce my experience in a simple example.
Direct Answer
The need to set up the relationships, i.e. to assign nose to face and face to node, isn't really awkward. Hibernate is a RELATIONSHIP mapper, so you need to make the relationships explicit. That said, you can write less code by defining a
setNose(nose){
this.nose = nose
nose.face = this
}
on Face. Now when you do face.nose = nose, the setter gets invoked for you, and the relationship is setup the way you want.
General Useful Thoughts
In general, you do not need to assign the relationship in both directions. It is perfectly valid to have unidirectional or bidirectional relationships.
However, hasOne definition has very specific implications. The documentation very clearly states the purpose of hasOne is to tell hibernate to put the key that defines the relationship in the child, in this case Nose. If you think carefully about it, you will realize that the relationship should be bidirectional. Here are the thought points:
1) you define the hasOne on Face (i.e. the parent).
2) even though you have defined hasOne on the parent, the underlying table that is affected is the child's table (i.e. the face_id column on Nose)
3) Since the foreign key is on the child, the child must have a reference to its parent. If it didn't, you would have a property on the child that is a foreign key but is not related to an object.
4) Remember, you are using the ORM's machinery to define the relationship. While you could manually add a face_id field to Nose, and set up the values in code (i.e. manage the relationship yourself and not let the ORM tool do it), the fact that you are using ORM explicitly means the ORM tool will manage the relationship for you.
EDIT -- now reading my answer, I was unconvinced, so I wrote a test. I defined the Face and Nose classes as shown in the hasOne documentation, but I did not define the Face on the Nose. I tried to make it unidirectional. I wrote a test to see what what happen. Here is the test
class FaceTests extends GroovyTestCase {
public void testStuff(){
Face face = new Face()
Nose nose = new Nose()
face.nose = nose;
face.save(flush:true)
assertNotNull face.id
assertNotNull nose.id
}
}
and the result is an exception that contains
hasOne property [Face.nose] is not bidirectional. Specify the other side of the relationship!
So the framework even makes sure, for you, that when you use hasOne, you have a bidirectional relationship.

Resources