Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to find node set having relationships to given nodes using neo4j

Is there an efficient way with given two nodes to find a set of their common nodes (with defined relationships).

For example, having nodes A1, B1, C1-C4 connected with relationships x and y:

A1 --x--> C1
A1 --x--> C2
A1 --x--> C3
B1 --y--> C2
B1 --y--> C3
B1 --y--> C4

a common node set for A1(x) and B1(y) would be [C2, C3].

like image 435
Jonas Avatar asked Jun 02 '10 08:06

Jonas


People also ask

How many nodes can a single relationship connect in Neo4j?

This will work in all versions of Neo4j that support the MATCH clause, namely 2.0. 0 and later. This is a minimum length of 3, and a maximum of 5. It describes a graph of either 4 nodes and 3 relationships, 5 nodes and 4 relationships or 6 nodes and 5 relationships, all connected together in a single path.

How do you create a relationship between two existing nodes in Neo4j?

To create a relationship between two nodes, we first get the two nodes. Once the nodes are loaded, we simply create a relationship between them. The created relationship is returned by the query.

Can relationships have properties in Neo4j?

The graphs in the Neo4j Graph Data Science Library support properties for relationships. We provide multiple operations to work with the stored relationship-properties in projected graphs. Relationship properties are either added during the graph projection or when using the mutate mode of our graph algorithms.

How are relationships stored in Neo4j?

Properties are stored as a linked list of property records, each holding a key and value and pointing to the next property. Each node and relationship references its first property record. The Nodes also reference the first relationship in its relationship chain. Each Relationship references its start and end node.


2 Answers

In Gremlin (http://gremlin.tinkerpop.com), this is expressed as such:

setA._().out('x').in('y').retain(setB).back(2)

Here is what each step does:

  1. start at setA (A1, A2, A3 in your example).
  2. start a Gremlin pipeline.
  3. take the outgoing "x" labeled edges from those setA vertices to C1, C2, and C3.
  4. take the incoming "y" labeled edges from C1, C2, and C3.
  5. filter out all steps that are not in setB (thus, only C2 and C3 paths exist).
  6. go back to what you saw 2 steps ago -- thus, C2 and C3.

Tada!

Good luck, Marko.

http://markorodriguez.com

like image 186
Marko A. Rodriguez Avatar answered Nov 14 '22 22:11

Marko A. Rodriguez


In many cases the structure of the domain can be leveraged to improve performance. Let's say that you know that in general your A entities have less x relationships compared to the number of y relationships on the B entities. Then you could traverse two steps from the A node and see where the B node shows up, and filter out the C nodes this way. Here's some code for this approach:

Set<Node> found = new HashSet<Node>();
for ( Relationship firstRel : a1.getRelationships( Reltypes.x, Direction.OUTGOING ) )
{
    Node cNode = firstRel.getEndNode();
    for ( Relationship secondRel : cNode.getRelationships( Reltypes.y, Direction.INCOMING ) )
    {
        Node bNode = secondRel.getStartNode();
        if ( bNode.equals( b1 ) )
        {
            found.add( cNode );
            break;
        }
    }
}

Another way would be to start two threads that scan the relationships from either side.

A third approach would be to create a specialized index that would help answering this kind of queries, which would obviously hurt insert performance.

like image 29
nawroth Avatar answered Nov 14 '22 21:11

nawroth