neo4j: one-directional / two-directional relationships? - nosql

So I looked into neo4j, and I may be using it in an upcoming project since its data model might fit my project very well. I looked through the docs but I still need an answer to this question:
Can I set relationships to be one-directional?
It seems that the neo4j people like movies so let's continue with that. If I have a graph like this:
Actor A -> [:Acts in] -> Movie B
then direction is obvious, because the nodes are different types.
But I like horror movies so...
Person A -> [:wants_to_kill] -> Person B
I need this relationship to be one-directional so if I query "Who does Person A want to kill?" I get Person B, if I query "Who does Person B want to kill?" I get nothing.
Sometimes I still need relationships to be two directional
Like:
Person A <-[:has_met] -> Person B
...which is obvious.
documentation says:
Relationships are equally well traversed in either direction. This means that there is
no need to add duplicate relationships in the opposite direction (with regard to
traversal or performance).
While relationships always have a direction, you can ignore the direction where it is
not useful in your application.
So docs say, relationships by default have an direction and I can ignore that if I wish.
Now this is where things get complicated:
Consider the following graph (and note the arrows)
Person A <- [:wants_to_kill] -> Person B
Person B -> [:wants_to_kill] -> Person C
Person C -> [:wants_to_kill] -> Person A
If I ignore the Directions for all [:wants_to_kill] I get false results
for "Who does Person A / C want to kill?"
If I knew which ones I had to ignore, I would not do the query.
So can I somehow set relationships to be two-directional (when creating them), or should I model this with two relationships (between Person A & B)?

A relationship in Neo4j always has a direction. If a relationship type's semantics do not incorporate a direction, e.g. has_met from your example, then it's best practice to apply an arbitrary direction on creation of the relationship. Querying is then done by using the "both directions" (there is no "larger/smaller than" character) notation in cypher:
start ... match (a)-[:HAS_MET]-(b) ....
In contrast, if the semantics of a relationship do have a direction like your wants_to_kill, you need to use two relationship to indicate that a and b wants kill the other one and vice versa. For the example above, you need to have 4 relationships:
Person A -[:wants_to_kill]-> Person B
Person B -[:wants_to_kill]-> Person A
Person B -[:wants_to_kill]-> Person C
Person C -[:wants_to_kill]-> Person A
To find all the person that A wants to kill you do:
start a=node:node_auto_index(name='A') match a-[:wants_to_kill]->victims_of_a return victims_of_a
To find all persons who want to kill A:
start a=node:node_auto_index(name='A') match murderer_of_a-[:wants_to_kill]->a return murderer_of_a

Related

Equivalence relations are to Groups, as partial order relations are to...?

I'm a beginning student of category theory so the question is a little hazy. Apologies if it is too basic.
An equivalence relation induces a "symmetric category" (bad terminology?), where you can back from any arrow. The category induced by a group has a different symmetry. How are these two specifically related? Is an equivalence relation somehow an algebra, like a group, that specializes the category axioms? Is it more deeply analogous to a group in some way?
I know that a category can also be induced by a partial order - which encodes anti-symmetry rather than symmetry . Is there a corresponding algebra encoding antisymetry (like a group but encoding anti-symmetry instead)? I know a partial order itself has the algebra of a lattice.
A set with an equivalence relation is often called a setoid. Categorically, a setoid is a thin groupoid. A groupoid may be thought of as a "multi-object group" in the same way that a category is a "multi-object monoid": that is, the endomorphisms of every object in a groupoid form a group.
A partial order is a thin skeletal category (a preorder is simply a thin category). Therefore, the algebraic structure corresponding to a partial order (or preorder), in the same way that groups correspond to equivalence relations, is a monoid.
The relationship "an X is just a one-object Y" is called horizontal categorification, where for your examples we have:
X = group, Y = groupoid.
X = monoid, Y = category.

How to build inverse relationship to Entity which has more than two relationship to it?

I have an entities Group and Person with relationships:
Group:
Group.leader -> Person (To One)
Group.looser -> Person (To One)
Group.others ->> Person (To Many)
In leader, looser and others set I could have different Person entities. Same Person could be leader in one group, looser in second and appears in others set in third group.
in Person entity I have To-Many relationship groups which should connect
Person:
Person.groups ->> Group (should be enough but warnings)
Because I can make only one inverse relationship I always
will have a warning "something should have inverse"
How to deal with relationships like this?
Or:
I have entities Cube, Plan and Line. Cube has relationships x, y, z, Plane x and y, Line just x. And I need to share some values between them, even sometimes mixed:
Cube:
Cube.x --> Value
Cube.y --> Value
Cube.z --> Value
Plane:
Cube.x --> Value
Cube.y --> Value
Line:
Cube.x --> Value
Value:
Value.counted -->> Line.x or Line.y, Plane.x, Cube.x, y, z, SomeAnotherEntity.neededValue
Apple recommend that every relationship should have an inverse. In your case, that would mean the Person entity would have three relationships:
Person.groupsLed ->> Group (to many) // "groups where this Person is leader"
Person.groupsLost ->> Group (to many) // "groups where this person is the looser"
Person.otherGroups ->> Group (to many) // "other groups with this person as a member"
which does seem rather complicated. One alternative would be to collapse the three relationships into one (for each of Person and Group) with an intermediate entity (Ranking?):
Group.rankings ->> Ranking (to many) // "the ranking of people for this group"
Person.rankings ->> Ranking (to many) // "the ranking of this person in different groups"
In each case the inverse would be to-one:
Ranking.person -> (Person) (to one) // "the person for this ranking"
Ranking.group -> (Group) (to one) // "the group for this ranking"
You can then add an attribute to the Ranking entity to indicate the leaders/loosers/other. That could be a simple string attribute rank which takes the values "leader", "looser" or "other", or an equivalent integer enum. To manage the relationship between a Group and a Person, you add or remove Ranking objects. One downside to all this is that finding the leader or looser involves filtering the rankings, but it does give you a degree of flexibility.

Event B Total Function

I have a question as follows:
A primary school class contains a number of children and a variety of books. Write a model which keeps track of the books that the children have read. It should maintain a relation hasread between children and books. It should also handle the following events:
record: adds the fact that the given child has read the given book
newbook: outputs a book that the given child has not already read
books_query: outputs the number of books the given child has read
Here is my model so far
CONTEXT
booksContext
SETS
STUDENTS
BOOKS
CONSTANTS
student
book
AXIOMS
axm1: partition(STUDENTS, {student})
axm2: partition(BOOKS,{book})
And my machine is as follows:
MACHINE
books
SEES
booksContext
VARIABLES
students
books
readBooks
INVARIANTS
students ⊆ STUDENTS
books ⊆ BOOKS
readBooks ∈ students → books
I have an event where I want mark a book as read for a given student. It takes in two parameters: the name of the student and the name of the book.
EVENTS
record
ANY
rbook
name
grd1: rbook ∈ books
grd2: name ∈ students
Now for the guards. I want to say
"If the student has not read the book already"
I had this but t doesn't work and I don't know what to do now. Can anyone help me
grd3: rbook(name) = ∅
rbook is just one book, but you are using is as if it was a function. Do you mean readBooks(name) = {}? If yes, the statement would still be "Has the student never read a book?".
The first problem is probably in the definition of readBooks. You modelled it as a total function from students to books. That means that every student has read exactly one book. That is probably not what you wanted to express. To state that every student has read an arbitrary number of books you can map students to sets of books:
readBooks : students --> POW(books)
The the guard would be rbook /: readBooks(name).
Personally I would prefer relations in such a case, they are usually easier to cope with. Here a pair s|->b would be in readBooks if student s has read book b:
readBooks : students <-> books
In that case the guard would be name|->rbook /: readBooks.

Core Data: How to design a tree data structure from one core data entry

I am struggling with designing a coreData model where I have only one type of entry called "To-Do". Each To-Do entry has either 0, 1, 2, ... , or n relationships to other (sub) entries just like To-Do. So the relationships between the To-Do entries design a tree structure with an undefined number of child nodes. The following graphic should illustrate the case (E = core data entry):
E
/|\
/ | \
E E E
/ \
/ \
E E
/|\
E E E
My guess was to model that data like illustrated in the following graph. I didn't choose the inverse relationship because Xcode made a many-to-many relationship out of it which doesn't match the tree design.
Also I saw in the data model inspector something called "parent entry". So I started to believe I might have to create a second entry named "To-Do-Child" with the same attributes and make the other entry to the parent entry. The manual tells me that this might be the wrong path to go...
Questions:
How can I model this approach within the core data model file? Is one of the ones mentioned correct?
How will I be able to fetch all To-Do entries of a specified parent node? Since they arise from the same entry I have problems to address the exact To-Do subtree I want.
I think you need a relationship of parent (destination entity is your to do entity) which serves as the destination for the inverse relationship.
Entries at the top of the tree have nil value for this relationship.
For any to-do item, the set returned from the childToDos relationship will hold all the children. It doesn't matter that these are of the same class.

Can Entity Framework map two associations into a single navigation?

I have two simple tables as described here...
Table = Person
PersonID (int, PrimaryKey)
FirstName (char)
LastName (char)
Table = Related
RelatedID (int, PrimaryKey)
Person1 (int, ForeignKey for Person.PersonID)
Person2 (int, ForeignKey for Person.PersonID)
Relationship (int)
The generated entity for Person has two navigation collections. One for the Related.Person1 and another for Related.Person2. This is a pain because it means I have two collections to investigate to look up all the relationships that are relevant to that person.
I need to have instead just a single navigation collections that contains both of these sets. Is it possible to have this generated as part of the entity frameowrk? The only alternative is to generate a third collection myself that contains the aggregate set of entities and it feels like that should not be needed.
As Craig states what you are asking for is not something core to EF but... a friendship type relationship is one of those nasty ones to model, so I see what you are trying to do.
There is a workaround to make this possible by mapping the Association Set to a view (DefiningQuery) in the SSDL.
The association/relationship backed by the view will then be read-only, so you will probably want to leave the other two relationships in place to allow you to add / remove from the correct collection or for when you want to search in one direction only.
Check out this post which shows the techniques involved for more.
Hope this helps
Alex