Chen Notation - whats the different between "N" and "M" when marking a relationship - entity-relationship

This might be a basic question, Im confused. Is there actually a different between M and N when using chen notation. I searched on this but couldn't find an explanation on why two characters if both represent the same thing.
I found :
The degree of relationship (cardinality) is represented by characters “1”, “N” or “M” usually placed at the ends of the relationships:
one-to-one (1:1)
one-to-many (1:N)
many-to-one (N:1)
many-to-many (M:N)
So why not (M:1) (1:M) and (N:N) or (M:M)?

M and N are simply just coefficient. It means there can be any number.
(N:M) can be (1:2) , (2:3) .. etc
But (N:N) or (M:M) includes (1,1) , (2,2) ,(3,3) ...
Basically to represent two different number we use different notations( here "N" and "M").
Yes, there CAN BE a case where N is equals to M.

Related

Compute the distances between two nodes and their lowest common ancestor (LCA)

I need to compute the distance that separate two nodes A and B with their lowest common ancestor in a graph. I use the followinf function to find LCA:
match p1 = (A:Category {idCat: "Main_topic") -[*0..]-> (common:Category) <-[*0..]- (B:Category {idCat: "Heat_transfer"})
return common, p1
Is there any function in Neo4j that allows to return the respective distance between d(A,common) and d(B, common).
Thank you fo your help
If I understand the lowest common ancestor correctly, this comes down to finding the shortest path between A and B with at least one node in between. That you can do using this query. Here the condition that the length of p is larger than 1 forces at least one node between the two. Below example uses the IMDB toy database and returns the movie Avatar.
match p=shortestPath((n:Person {name:'Zoe Saldana'})-[r*1..15]-(n1:Person {name:'James Cameron'})) where length(p) > 1 return nodes(p)[1]
Basically you can choose any element from the nodes in the path, except the first and last one (since those will be A and B)

Good way to set relation to an edge in Neo4j

For my project I need to create a relation to an edge in Neo4j graph database.
Let's illustrate on example of a flight provider who operates flights from Rome to London (and back) and also from Oslo to Lisbon.
CREATE (l:City{name:"London"})
(r:City{name:"Rome"}),
(li:City{name:"Lisbon"})
(o:City{name:"Oslo"}),
(op:Operator{name:"One"}),
(l)<-[f:FlightRoute{distance:900}]->(r)
How would you link Operator One to London, Rome, Lisbon and Oslo to suggest that this operator connects these cities (l<-->r & li<-->o) but not e.g. r<-->o. Other operators would be doing other cities. So basically I would like to link op to 2 edges.
Queries to perform would be to find all operators doing various lines. Calculating overall distances of operations (assuming <--> has distance parameter) etc.
I can imagine only to create a node between (l) and (r). Is there some other way?
As you suspected, "reification" (i.e., turning a relationship into a node) is probably the best way to handle your situation.
Here is an example of a query that adds the fact that an operator operates a flight from London to Rome:
MATCH (l:City {name:"London"}),
(r:City {name:"Rome"}),
(op:Operator {name:"One"})
CREATE (l)<-[:FROM]-(f:FlightRoute{distance:900})-[:TO]->(r),
(op)-[:OPERATES]->(f);
And a similar query for a flight from Lisbon to Oslo:
MATCH (li:City {name:"Lisbon"}),
(o:City {name:"Oslo"}),
(op:Operator {name:"One"})
CREATE (li)<-[:FROM]-(f:FlightRoute{distance:21})-[:TO]->(o),
(op)-[:OPERATES]->(f);
To find all operators between London and Rome:
MATCH (l:City {name:"London"})<-[:FROM|TO]-(f)-[:FROM|TO]->(r:City {name:"Rome"}),
(op:Operator)-[:OPERATES]->(f)
RETURN DISTINCT op;
To find overall distance for all flights of an operator:
MATCH (op:Operator {name:"One"})-[:OPERATES]->(f)
RETURN SUM(f.distance);
Indexes (or uniqueness constraint) for :City(name) and Operator(name) would help to speed up the above queries.

Naming relationships changes the results?

Consider both queries:
[1]
MATCH (p1:Person)-[ACTED_IN]->(m1:Movie), (p2:Person)-[DIRECTED]->(m1)
WHERE p1 = p2
RETURN p1.name
[2]
MATCH (p1:Person)-[xa:ACTED_IN]->(m1:Movie), (p2:Person)-[xd:DIRECTED]->(m1)
WHERE p1 = p2
RETURN p1.name
The only difference is xa: and xd:, the relationship aliases.
The difference in result is much bigger:
Query 1 has 32 rows. Every person has at least 2 rows, some have 6.
Query 2 has 3 rows. All 3 are different.
Aliasing 1 XOR the other has even different results: 4 or 10 rows.
Why? There's no aggregation. The relationship aliases are unused. Why does it change the query?
Database is free example db 'Movie graph' on https://app.graphenedb.com/ (but it's private).
You've mixed up the syntax of what differentiates a variable from a relationship type. In your first match, because there is no : character, ACTED_IN and DIRECTED are variables, matching to any relationship type, and throwing off your matched results.
:ACTED_IN and :DIRECTED are what you meant to use, because the prefixed : denotes them as relationship types.
It works the same way with node labels and variables, with a token prefixed by : indicating a node label, and the token before the colon used as an variable (or if no : is present, there is no label and the entire thing is an variable).
EDIT
Here are a few examples of relationship syntax, pointing out the relevant parts:
In this one, ACTED_IN is a variable for all relationships between p1 and m1.
(p1:Person)-[ACTED_IN]->(m1:Movie)
In this one, :ACTED_IN is the relationship type between p1 and m1, and no variable is present
(p1:Person)-[:ACTED_IN]->(m1:Movie)
In this one, :ACTED_IN is the relationship type between p1 and m1, and 'a' is the variable bound to the matched relationships.
(p1:Person)-[a:ACTED_IN]->(m1:Movie)
This one is invalid syntax, since there must be a token after the : to act as the relationship type.
(p1:Person)-[a:]->(m1:Movie)

Getting a node's neighbors but respecting the direction of the relationship

For example purposes, I am using this site.
Say we want to know who Morpheus knows, but we want to to retain the direction of the relationship. I want a to be the "from" and b to be the "to"
This returns all three relationships, but the direction is lost:
MATCH (a { name:"Morpheus" })-[]-(b:Crew) RETURN a, b
Further, Morpheus is always a... doh.
Take 2 was to let Morpheus be a or b:
MATCH (a:Crew)-[]-(b:Crew) WHERE a.name="Morpheus" OR b.name="Morpheus"
RETURN a, b
This returns twice as many rows as I expected. Apparently the [] relation is very free with its matches.
After some spelunking, I realized I was focusing on the wrong thing:
MATCH ({ name:"Morpheus" })-[r:KNOWS]-()
RETURN startnode(r) AS a, endnode(r) AS b
This does the trick. 3 rows back with the relationship direction respected.
I feel a little weird about not naming the nodes at all in that query. It feels like I am hacking. But then again, tying nodes together is what relationships are for. What are some other ways to do the same thing?
You should be able to combine the two approaches:
MATCH (knower:Crew)-[:KNOWS]->(knowee:Crew)
WHERE knower.name="Morpheus" OR knowee.name="Morpheus"
RETURN knower, knowee

neo4j cartesian product performance improvement

I have a Graph database with over 2 million nodes. I have an application which takes a social graph and does some inference on it. As one step of the algorithm, I have to get all possible combinations of a relationship [:friends] of two connected nodes. Currently, I have a query which looks like:
match (a)-[:friend]-(c), (b)-[:friend]-(d) where id(a)={ida} and id(b)={idb} return distinct c as first, d as second
So, I already know the nodes a and b and I want to get all the possible pairs that can be made from friends of a and b.
This is obviously a very slow operation. I was wondering if there is a more efficient way of getting the same result in neo4j. Perhaps adding indexes might help? Any ideas / clues are welcome!
Example
Node a has friends : x, y
Node b has friends : g, h, i``
Then the result should be:
x,g
x,h
x,i
y,g
y,h
y,i`
If you are not already you should use labels to speed up your query, which might look like:
MATCH (p1:Person)-[:FRIEND]->(p3:Person),(p2:Person)-[:FRIEND]->(p4:Person)
WHERE ID(p1) = 6 AND ID(p2) = 7
RETURN p3 as first, p4 as second
Obviously that will rely on you having created your nodes with a :Person label.
How many friends does the average node have?
I wouldn't use two patterns but just one and the IN operator.
MATCH (p:Person)-[:FRIEND]->(friend:Person)
WHERE id(p) IN [1,2,3]
RETURN p, collect(friend) as friends
Then you have no cross product and you can also return the friends nicely as collection per person.

Resources