neo4j : How to Create the bidirectional Relationships in graph database? - neo4j

I tried to create bidirectional relationships by using this pattern (u1)-[:]-(u2) and also this one (u1)<-[:]->(u2).
but at the end result is directed to one part of the nodes from the first parenthesis to last one (u1)-[:]->(u2).
How to achieve bidirectional relationships here?

I think Neo4j cannot store bidirectional relationships.
No way around this, however, you can treat relationships as bidirectional when querying your graph.

Related

Collapse Relationships Neo4j?

Is it possible to "collapse" relationships in neo4j? I'm trying to graph relationships between people, and they can be related in multiple different ways - a shared course, jointly authored paper, RT or tweet mention. Right now I'm modeling people, courses, papers, and tweets all as nodes. But what I'm really interested in is modeling the person-person relationships that go through these intermediary nodes. Is it possible to graph the implicit relationship (person-course-person) explicit (person-person), while still keeping the course as a node? Something like this http://catalhoyuk.stanford.edu/network/teams/ - slide 2 and 3.
Any other data modeling suggestions welcome as well.
Yes, you can do it. The query
MATCH(a:Person)-->(:Course)<--(b:Person)
CREATE (a)-[:IMPLICIT_RELATIONSHIP]->(b)
will crate a relationship with type :IMPLICIT_RELATIONSHIP between all people that are related to the same course. But probably you don't need it since you can transverse from a to b and from b to a without this extra and not necessary relationship. Also if you want a virtual relationship at query time to use in a projection you can use the APOC procedure apoc.create.vRelationship.
The APOC procedures docs says:
Virtual Nodes and Relationships don’t exist in the graph, they are
only returned to the UI/user for representing a graph projection. They
can be visualized or processed otherwise. Please note that they have
negative id’s.

Why neo4j don't allows not directed or bidirectional relationships at creation time?

I know that Neo4j requires a relationship direction at creation time, but allows ignore this direction in query time. By this way I can query my graph ignoring the relationship direction.
I also know that there are some workarounds for cases when the relationships are naturally bidirectional or not directed, like described here.
My question is: Why is it implemented that way? Has a good reason to not allow not directed or bidirectional relationships at creation time? Is it a limitation of the database architecture?
The Cypher statements like below are not allowed:
CREATE ()-[:KNOWS]-()
CREATE ()<-[:KNOWS]->()
I searched the web for an answer, but I did not find much. For example, this github issue.
Is strange to have to define a relationship direction to one that don't have it. It seems to me that i'm hurting the semantic of my graph.
EDIT 1:
To clarify my standpoint about a "semantic problem" (maybe the term is wrong):
Suppose that I run this simple CREATE statement:
CREATE (a:Person {name:'a'})-[:KNOWS]->(b:Person {name:'b'})
As result i have this very simple graph:
The :KNOWS relationship has a direction only because Neo4j requires a relationship direction at creation time. In my domain a knows b and b knows a.
Now, a new team member will query my graph with this Cypher query:
MATCH path = (a:Person {name:'a'})-[:KNOWS]-(b:Person {name:'b'})
return path
This new team member don't know that when I created this graph I considered that :KNOWS relationship is not directed. The result that he will see is the same:
By the result this new team member can think that only Person a consider knows Person b. It seems to me bad. Not for you? This make any sense?
Fundamentally, it boils down to the internals of how the data is stored on disk in Neo4j -- note Chapter 6 of the O'Reilly Neo4j e-book.
In the data structure of a relationship they have a "firstNode" and a "secondNode", where each is either the left or the right hand side of the relationship.
To flag a relationship as uni/bi-directional would require an additional bit per node, where I would argue it is better to retain the direction in the data store and just ignore direction during querying.
In Neo4j relationships are always directed.
But if you don't care about the direction, you can ignore the direction when querying.
MATCH (p1:Person {name:"me"})-[:KNOWS]-(p2)
RETURN p2;
And with MERGE you can also leave off the direction when creating.
MATCH (p1:Person {name:"me"})
MATCH (p2:Person {name:"you"})
MERGE (p1)-[:KNOWS]-(p2);
You only need 2 relationships if they really convey a different meaning, e.g. :FOLLOWS on Twitter.
It seems to me that i'm hurting the semantic of my graph.
I can't see why a < or > symbol used during creation of a relationship hurts the semantics of your graph if you are going to not use that symbol during matching (and thus treating that relationship as undirected/bidirectional).
Suppose that the syntax proposed by you is supported. Now how will you connect with an undirected relationship two nodes a and b? You still have two options:
CREATE (a)-[:KNOWS]-(b)
CREATE (b)-[:KNOWS]-(a)
The pair (a, b) is always ordered by appearance even if not by semantics. So even if we remove the < or > symbol from the relationship declaration, the problem with the order of nodes in it cannot be eliminated. Therefore simply don't treat it is a problem.

Returning on-the-fly relationship in graph form in Neo4j

I'm pretty new to Neo4j and graph DBs in general, and have been playing around with it for the last few days. I've now hit something I'm stumped on: I'm trying to create a "temporary" relationship between two disjoint nodes just for the sake of a RETURN, then not store this relationship within the DB afterwards.
The dataset I'm using is a graph of Movie and Person nodes provided in one of the basic Neo4j built-in tutorials. My query is currently as follows:
MATCH (p1:Person)-[r1:ACTED_IN]-(m1:Movie)-[r2:ACTED_IN]-(p2:Person)
WHERE p1.name="Kevin Bacon"
RETURN {start:p1,rel:"COSTAR",end:p2}
What I'd ultimately like to see is a central "Kevin Bacon" node with COSTAR relationships to a series of Person nodes around it, without any Movie nodes or ACTED_IN relationships being displayed. The query above does show the COSTAR relationship in the returned rows, but it does not appear on the graph itself; I've attached a few screenshots of what I'm seeing.
The only other idea I have is to use the MERGE keyword to create a COSTAR relationship, but (as I understand it) this actually stores the relationship in the DB which is what I'm trying to avoid.
Any suggestions would be greatly appreciated.
The neo4j Browser only visualizes nodes and relationships that actually exist in the DB. So, there is no way to do what you want without actually creating the COSTAR relationships, visualizing the result in the Browser, and then deleting all the COSTAR relationships.
As a workaround you could simply display the nodes of all of Kevin Bacon's costars, like this:
MATCH (p1:Person)-[:ACTED_IN]-(:Movie)-[:ACTED_IN]-(p2:Person)
WHERE p1.name="Kevin Bacon"
RETURN DISTINCT p2;
So you want the relationships to appear in the graph visualization in the Neo4j browser but not store these relationships in the graph itself? I can't think of a way to make that happen (without hacking it), but would deleting the relationships after you are done generating the visual work?
Query to create COSTAR relationships:
MATCH (p1:Person)-[r1:ACTED_IN]-(m1:Movie)-[r2:ACTED_IN]-(p2:Person)
WHERE p1.name="Kevin Bacon"
CREATE UNIQUE (p1)<-[:COSTAR]-(p2);
Execute your query to populate the graph in Neo4j Browser...
Then to delete the COSTAR relationships:
MATCH (:Person)-[r:COSTAR]-(:Person)
DELETE r;
The best way to achieve this (now... 6 years later) is with the gds.graph.create.* functions (assuming you load GDS)
https://neo4j.com/docs/graph-data-science/current/graph-create/
With a graph as simple as this, gds.graph.create(...) would be enough (creating COSTAR for all co-starrings)
Or, if you wanted to do some constraining, gds.graph.create.cypher(...)
The in-memory graph projection feels like what you wanted to achieve - it persists only as long as the DBMS is active, or until you call gds.graph.drop(...)

Neo4j Bidirectional Relationship

Is there a way to create bidirectional relationship in Neo4j using Cypher? I would like the relationship to be bidirectional rather than making two unidirectional relationships in both directions For eg:
(A)<-[FRIEND]->(B)
Rather than:
(A)-[FRIEND]->(B)
(A)<-[FRIEND]-(B)
Thanks in advance :)
No, there isn't. All relationships in neo4j have a direction, starting and ending at a given node.
There are a small number of workarounds.
Firstly, as you've suggested, we can either have two relationships, one going from A to B and the other from B to A.
Alternatively, when writing our MATCH query, we can specify to match patterns directionlessly, by using a query such as
MATCH (A)-[FRIEND]-(B) RETURN A, B
which will not care about whether A is friends with B or vice versa, and allows us to choose a direction arbitrarily when we create the relationship.
According to this article: Modeling Data in Neo4j: Bidirectional Relationships
The strictly better choice is to create a relationship in an arbitrary direction and not specify the direction when querying:
MATCH (neo)-[:PARTNER]-(partner)
The engine is capable of traversing the edge in either direction. Creating the anti-directional edge is unnecessary and only serves to waste space and traversal time.

How to create a new relationship in Neo4j, starting from an existing one, using a Cypher query?

Is there a simple way to create a new relationship in Neo4j, starting from an existing one?
Starting from the actor-director-movie database used in the tutorials, what I would like to do is to get all the {(actor1),(actor2)} couples of nodes in the graph satisfying the relationships:
(actor1)-[:ACTED_IN]->(movie)<-[:ACTED_IN]-(actor2)
and use them to create a new relationship like:
(actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
in whatever direction (I am interested in both directed and undirected graphs).
Is there a way to do this with a simple Cypher query?
Many thanks,
sTe
Using the sample movie dataset:
MATCH (actor1:Person)-[:ACTED_IN]->(:Movie)<-[:ACTED_IN]-(actor2:Person)
WITH actor1, actor2
MERGE (actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
I'd do that :
MATCH (actor1)-[:ACTED_IN]->()<-[:ACTED_IN]-(actor2)
CREATE UNIQUE (actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
which is basically what you said. Relations are uni-directional (no way around), but the api (Cypher queries or Traversal) can read them both ways (so it doesn't really matter which way your create them in some cases).
To check if what you did is ok, you can run the following :
MATCH (actor1)-[:ACTED_IN_SAME_MOVIE]-(actor2)
RETURN actor1, actor2

Resources