Modeling a relationship that relies on two nodes - neo4j

I'm modeling legal cases with Attorneys, Firms, Judges, Cases and Parties and I'm trying to model the relationship between an Attorney and a Party on a Case. The trouble is that my current model doesn't scope the relationship to a particular case, that is, once an Attorney has a REPRESENTS relationship to a Party, then she is always associated with that Party, even on unrelated Cases. I know that relationships can only have two nodes on them, so how do I model this without creating a SQL-like join table? That is, I want this (even though I can't have it):
(Attorney)-[REPRESENTS]->(Party+Case)
Here's a simplified sketch of my models:
(Attorney {email:, ...})
-[REPRESENTS]->(Party)
-[MEMBER_OF]->(Firm)
(Party {name:, ...})
-[PARTY_IN {role: <plaintiff, defenadant, ...>}]->(Case)
(Firm {email_domain:, ...})
(Case {title:, case_number:, court_house:, ...)
(Judge {name:,...})
-[PRESIDING_OVER]->(Case)

Look into the use of intermediate nodes. Not a perfect example, but this might help you think through the data model.
http://www.markhneedham.com/blog/2013/10/22/neo4j-modelling-hyper-edges-in-a-property-graph/
The idea is that you might want to create a relationship node that connects the Case, Party, and Attorney

Seems like you may want to break out your PARTY_IN roles as their own nodes.
So you might have something like this:
(:Party)-[:PARTY_AS]->(:Defendant)-[:IN]->(:Case)
(:Attorney)-[:REPRESENTS]->(:Defendant)-[:IN]->(:Case)
You can either use separate labels for :Defendant, :Plaintiff, etc (recommended), or have a more generalized (:Role) with a type field.
If you wanted a query to give you the parties and attorneys for a case, you might use something like:
MATCH (case:Case)
WHERE case.id = 123
WITH case
MATCH (party:Party)-[:PARTY_AS]->(role)-[:IN]->(case)
WITH party, role
MATCH (attorney:Attorney)-[:REPRESENTS]->(role)
RETURN LABELS(role) AS role, COLLECT(attorney) AS attorneys, party
(using collect here as multiple attorneys may represent a party in a case)

Related

Developing graph database model for department/supplier/items

I'm currently ramping up on graph databases and to do that am working through a set of questions to learn Cypher. However, I'm not 100% happy with the design I've chosen since I have to match relationships to nodes to make some of the queries work.
I found Neo4j: Suggestions for ways to model a graph with shared nodes but has a unique path based on some property with some suggestions that are relevant, but they involve copying nodes (repeating them) when in fact they do represent the same thing. That seems like an update issue waiting to happen.
My design currently has
(:Dept {name,floor})-[:SOLD {quantity}]->(:Item {name,type})<-[:SUPPLIES {dept,volume)]-(:Company {name,address})
As you can see, to figure out which department a company supplied an item to, I have to check the :SUPPLIES dept property. This leads to somewhat awkward queries - it feels that way to me, anyway.
I've tried other relationships, like having (:Company)-[:SUPPLIES {item,vol}]->(:Dept) but then the problem just shifts to matching :SUPPLIES relationship properties to :Item nodes.
The types of queries I am building are of the nature: Find departments that sell all of the items they are supplied.
Is there some other way to model this that I am overlooking? Or is this sort of relationship, where a supplier is related to two things, an item and a department, just something that doesn't fit the graph model very well?
You want to store and query a triangular relationship between :Dept, :Item, and :Company. This can't be accomplished by a linear relationship pattern. Comparing IDs of entities is not the Neo4j way, you would neglect the strengths of a graph database.
(Assuming that I understood your use case scenario) I would introduce an additional node of type :SupplyEvent that has relationships to :Dept, :Item, and :Company. You could also split up :SOLD relationship in a similar way, if you want relations between department, item, and, e.g., a customer.
Now, you can query all companies that supplied which items to which departments (without comparing any IDs):
MATCH (company:Company)<-[:SUPPLIED_FROM]-(se:SupplyEvent)-[:SUPPLIED_TO]->(dept:Dept),
(se)-[:SUPPLIED]->(item:Item)
RETURN company, item, dept

Node based properties on a relationship

I'm starting out with Neo4J to create a graph of users and their relationships. At the moment there is a single 'KNOWS' relationship between users i.e.
What I want to do now is specify properties on the relationship specifically for each of the users. For example, "interest" which indicates how much a user is interested in the other user. Can I specify this for each user on a single KNOWS relationship or would I need to create two relationships between the users and set the attribute on each of the relationships?
Any help would be appreciated.
Can I specify this (property: interest) for each user on a single KNOWS relationship or would I need to create two relationships between the users and set the attribute on each of the relationships?
You will need two relationships.
You could do it with one but then you have to keep two properties in the relationship and information about which property goes with which node. Much easier with two relationships.
From comment:
Can I keep them as bi-directional or would I need to use directional
in this case?
Relationships are always directional. It is only when you query that the concept of bi-directional appears, but that is not really bi-directional, it is without direction, e.g. (a)-[r]-(b). So you would use (a)-[r]->(b) and (b)-[r]->(a) or (a)<-[r]-(b). If you query with the direction, then you know how to apply the relationship property.
I typically do more of my work with Java as an embedded application instead of Cypher and it pays to use directional queries as it makes for less code to do the associations.
Note
Since your case is so simple, just try various methods and see what works. Remember to keep track of how long the quires take and if necessary add indexes. Also use the query profiling tool to make sure you are making effective queries.

Creating a relationship to a relationship in Neo4j

Is it possible to create a relationship to a relationship in Neo4j?
The use-case goes something like this:
I have a bunch of questions, like "What movie should we see?"
Each question can have many options like "Movie1", "Movie2", etc.
For each question I want a user to be able to vote for their favorite option.
The graph would preferably look something like this:
(:Question {name:"What movie?"})-[:Option]->(:Movie {name:"Movie1"})
^
|
[:Vote]
|
(:User)
I realize that one way I could solve this is with the following:
(:Question)-[:Option]->(:Movie)<-[:Vote]-(:User)
But then if I decide to remove the Movie as an Option in the future, I don't get to take advantage of DETACH and will have to manage removing the Vote relationship myself. Not to mention, if the Movie belongs to multiple categories, I have to keep track of which Question->Movie relationship it belongs to (probably with some sort of ID). It just seems very messy...
Is is possible to create a relationship to a relationship? Or am I going to have to manually enforce referential integrity?
Is is possible to create a relationship to a relationship?
No. This is not possible. According the docs:
A relationship connects two nodes, and is guaranteed to have a valid
source and target node.
That is: the start and end point of a relationship should be a node.
I believe you should do some changes in your data model. For example:
Maybe the Option can be a node and not a relationship. Make more sense, not? This way:
(:Category)-[:HAS]->(:Option)
Also, the Vote can be a node too, and not a relationship... This way, when the user makes (a relationship, ahn?) a vote, this vote node will reference the option and the category that it is relative to.
(:Category)-[:HAS]->(:Option)
\ /
[:FOR_CATEGORY][:FOR_OPTION]
\ /
(:Vote)
|
[:MAKES]
|
(:User)
If, for example, you need to delete a Option and consequently the :Votes related to it you can do something like:
MATCH (o:Option {id:10})<-[:FOR_OPTION]-(v:Vote)
DETACH DELETE o
DETACH DELETE v
Make any sense? Sorry for my ASCII art. :)
I'm investigating this. The only reasonable way I can find is to assign an identifier to the relationship (:HAS in your case) and then use it in the pointing relationship (:VOTE).
Neo4j has internal IDs for this (see the ID() function), but I usually prefer to try to assign a semantically meaningful ID (like a person's national insurance number, a page URL or, in case of relations, the hash code of its concatenated endpoint's identifers).

Can two models belong_to each other?

I have two models which are one-to-one to each other. A currently has one B.
Lately I encounter many cases where it is desirable if A keeps the id of B in order to simplify logic and boost performance. However I wonder if:
this is possible
would breach and convention
any thoughts really
UPDATE
I was wrong, the left outer join would not be benefited by the extra foreign key.
The only place I can think of is to find all A's which does not have B, an inner join is required on each of my 100000+ records. But if there is an id then I can know straight away which A has a B.
I don't believe this is possible - you have to decide where to keep the foreign key. Would it make sense for you to use a joining through relationship and for both your existing models to be has_one through the join?
Another alternative is to put A id on B, i.e. denormalize. This would allow you to figure out which A's without a B, and A's with a B. This might be appropriate for reporting scenarios when B's don't move between A's often.

SQL Relationships

I'm using MS SQL Server 2008R2, but I believe this is database agnostic.
I'm redesigning some of my sql structure, and I'm looking for the best way to set up 1 to many relationships.
I have 3 tables, Companies, Suppliers and Utilities, any of these can have a 1 to many relationship with another table called VanInfo.
A van info record can either belong to a company, supplier or utility.
I originally had a company_id in the VanInfo table that pointed to the company table, but then when I added suppliers, they needed vaninfo records as well, so I added another column in VanInfo for supplier_id, and set a constraint that either supplier_id or company_id was set and the other was null.
Now I've added Utilities, and now they need access to the VanInfo table, and I'm realizing that this is not the optimum structure.
What would be the proper way of setting up these relationships? Or should I just continue adding foreign keys to the VanInfo table? or set up some sort of cross reference table.
The application isn't technically live yet, but I want to make sure that this is set up using the best possible practices.
UPDATE:
Thank you for all the quick responses.
I've read all the suggestions, checked out all the links. My main criteria is something that would be easy to modify and maintain as clients requirements always tend to change without a lot of notice. After studying, research and planning, I'm thinking it is best to go with a cross reference table of sorts named Organizations, and 1 to 1 relationships between Companies/Utilities/Suppliers and the Organizations table, allowing a clean relationship to the Vaninfo table. This is going to be easy to maintain and still properly model my business objects.
With your example I would always go for 'some sort of cross reference table' - adding columns to the VanInfo table smells.
Ultimately you'll have more joins in your SP's but I think the overhead is worth it.
When you design a database you should not think about where the primary/foreign key goes because those are concepts that doesn’t belong to the design stage. I know it sound weird but you should not think about tables as well ! (you could implement your E/R model using XML/Files/Whatever
Sticking to E/R relationship design you should just indentify your entity (in your case Company/supplier/utilities/vanInfo) and then think about what kind of relationship there is between them(if there are any). For example you said the company can have one or more VanInfo but the Van Info can belong only to one Company. We are talking about a one – to- many relationship as you have already guessed. At this point when you “convert” you design model (a one-to many relationship) to a Database table you will know where to put the keys/ foreign keys. In the case of a one-to-Many relationship the foreign key should go to the “Many” side. In this case the van info will have a foreign keys to company (so the vaninfo table will contain the company id) . You have to follow this way for all the others tables
Have a look at the link below:
https://homepages.westminster.org.uk/it_new/BTEC%20Development/Advanced/Advanced%20Data%20Handling/ERdiagrams/build.htm
Consider making Com, Sup and Util PKs a GUID, this should be enough to solve the problem. However this sutiation may be a good indicator of poor database design, but to propose a different solution one should know more broad database context, i.e. that you are trying to achive. To me this seems like a VanInfo should be just a separate entity for each of the tables (yes, exact duplicate like Com_VanInfo, Sup_VanInfo etc), unless VanInfo isn't shared between this entities (then relationships should be inverted, i.e. Com, Sup and Util should contain FK for VanInfo).
Your database basically need normalization and I think you're database should be on its fifth normal form where you have two tables linked by one table. Please see this article, this will help you:
http://en.wikipedia.org/wiki/Fifth_normal_form
You may also want to see this, database normalization:
http://en.wikipedia.org/wiki/Database_normalization

Resources