Skip to content

Neo4j::Cypher Match

andreasronge edited this page Oct 1, 2012 · 16 revisions

Pattern matching is one of the pillars of Cypher. The pattern is used to describe the shape of the data that we are looking for. Cypher will then try to find patterns in the graph — these are called matching sub graphs. See the Neo4j Documenation on Match

Match Operators and Methods

The neo4j-cypher DSL uses the following matching methods/operators: <, >, >>, <<, <=> and both, outgoing and incoming methods. The <<, <=> and >> is used when you want to navigate any relationships. The other operators and method allows you to specify which relationship(s) to navigate.

Before reading this page please read about how to specify relationship patterns, nodes and variables here: Neo4j::Cypher-Start See Neo4j::Cypher-Return how to specify which value or values should be returned from a match.

Return Values

One difference between using the outgoing method and the > operator is that the outgoing method will return the end node and the operator (<,>, etc...) will return the path.

Example, return the path from node 3 navigating outgoing relationship of type friends

node(3) > :friends > node

Generates: START v1=node(3) MATCH v3 = (v1)-[:`friends`]->(v2) RETURN v3

Example, return the end node navigating from node 3 outgoing relationship of type friends.

node(3).outgoing(:friends)

Generates: START v1=node(3) MATCH (v1)-[:`friends`]->(v2) RETURN v2

Related nodes, <=>

The method <=> will generate a pattern match without regard to type or direction.

Example, return all incoming and outgoing paths from node 2.

node(3) <=> node

Generates the following strings: START v1=node(3) MATCH v3 = (v1)--(v2) RETURN v3

Unknown Type, Outgoing Node, >>

You can specify the direction of a relationship to match. Example: match all outgoing relationship of any type

node(3, 4) >> :x

See below for the outgoing method, which works in a similar way (it returns the node instead of the path).

Unknown Type, Incoming Node, <<

This will generate: START v1=node(3,4) MATCH v2 = (v1)-->(x) RETURN v2

Example: match all incoming relationship of any type and return those incoming nodes:

node(3, 4) << node.ret

This will generate: START v1=node(3,4) MATCH (v1)<--(v2) RETURN v2 See below for the incoming method, which works in a similar way (it returns the node instead of the path).

Outgoing or Incoming of a Type, -

If you don't want to specify the direction of the relationship but only the type of relationship you can use the - operator:

node(3) - ':knows|friends' - :foo
:foo
# Same as "START n0=node(3) MATCH (n0)-[:knows|friends]-(foo) RETURN foo"

Outgoing of a Type, >

Example, find all outgoing nodes navigating relationships of type friends:

node(3) > :friends > node(:x).ret

Will generate: START v1=node(3) MATCH (v1)-[:friends]->(x) RETURN x

Incoming of a Type, <

Example, find all incoming relationship of type friends to a node and return the path.

node(3) < rel(':friends') < node

Will generate: START v1=node(3) MATCH v3 = (v1)<-[:friends]-(v2) RETURN v3

#outgoing, #incoming and #both

The outgoing, incoming and both method works a bit similar to the <<, >>, <=> operators. Instead of returning the path it will return the last node.

Example:

node(3).both # same as node(3).both(rel)

This will generate the following string START v1=node(3) MATCH (v1)-[?]-(v2) RETURN v2

The outgoing, incoming and both methods also excepts rel object(s), string(s) or symbol(s).

outgoing one relationship

Example, only navigate an outgoing relationship of a specific type:

  node(2).outgoing(:friends)

Same as START v1=node(2) MATCH (v1)-[:`friends`]->(v2) RETURN v2 Notice, unlike the >> operator the return value is the v2 node.

The same match can also be expressed using the rel method, example:

  node(2).outgoing(rel(:friends))

outgoing several relationships

Here are different ways of writing a DSL for navigating several outgoing relationship types.

node(3).outgoing(rel(:friends, :work, :family))

Generates START v1=node(3) MATCH (v1)-[:`friends`|`work`|`family`]->(v2) RETURN v2'

Or

node(3).outgoing(rel(:friends), rel(:work), rel(:friends))

Or

node(3).outgoing(:friends, :work, :family)

Variable Depth

The depth of the match be specified in the rel method.

Example, returns the relationships, if there is a path between 1 and 3 relationships away.

node(3).outgoing('r:KNOWS*1..3')
:r

This generates: START v1=node(3) MATCH (v1)-[r:KNOWS*1..3]->(v2) RETURN r

Similar to:

node(3) > rel(':KNOWS*1..3').ret > :someone

Which generates: START v2=node(3) MATCH (v2)-[v1:KNOWS*1..3]->(someone) RETURN v1

Combinding #outgoing, #incoming and #both

You can combine the outgoing, incoming and both methods to navigate several relationships in one go.

node(3).outgoing(:friends).incoming(:friends).outgoing(:place)

This generates the following: START v1=node(3) MATCH (v1)-[:friends]->(v2),(v2)<-[:friends]-(v3),(v3)-[:place]->(v4) RETURN v4

The Match Block

All start nodes and node variables has a match, which allows you use a another ruby block for the match expression. This can be used to avoid using variables and instead rely on method chaining.

Example:

node(3,4).match{|n| n <=> node(5) }

Same as START v1=node(3,4),v2=node(5) MATCH (v1)--(v2) RETURN v1

A more complex example (but silly):

node(3,4).match{|n| n >> :friends} >> :work

Same as 'START v1=node(3,4) MATCH (v1)-->(friends),v2 = (v1)-->(work) RETURN v2`

Binding Matching Nodes to Variables

It is often useful to assign a variable to a paths, relationships or nodes. By doing that you can use the variable as a condition in the WHERE clause or in the RETURN clause.

You can do that in two ways.

Using Ruby Variables

Since we have access to the full ruby language we can also use ruby variables (of course).

Example: return all outgoing nodes with property name equal 'andreas'

x = node
node(3) >> x
x[:name] == 'andreas'
x

In the example above a new cypher variable name will automatically be created and used as a normal Ruby variable (x)

Using Cypher Identifiers

This example will instead create a cypher node variable x

node(3) >> node(:x)
node(:x)[:name] == 'andreas'
:x 

Same as START v1=node(3) MATCH (v1)-->(x) WHERE x.name = "andreas" RETURN x

Another example:

node(3).outgoing(:friends).as(:a).incoming(:friends).as(:b).outgoing(:place).as(:c)

Same as START v1=node(3) MATCH (v1)-[:friends]->(a),(a)<-[:friends]-(b),(b)-[:place`]->(c) RETURN c'

Predicates

Predicates are commonly used to filter out subgraphs in the WHERE part of a query, see http://docs.neo4j.org/chunked/1.8/query-function.html

Example: Tests whether a predicate holds for all element of this collection collection.

(node(3)>'*1..3'>node(1)).nodes.all?{|n| n[:age] > 30} 

Generates: START v2=node(3),v3=node(1) MATCH v1 = (v2)-[*1..3]->(v3) WHERE all(x in nodes(v1) WHERE x.age > 30) RETURN nodes(v1)

Other predicate methods are: any? none? single?

Scalar functions: Length

Scalar functions return a single value, see http://docs.neo4j.org/chunked/1.8/query-function.html

Example: To return or filter on the length of a collection, use the LENGTH() function

node(3) >> :b >> :c).length

Generates cypher: START v1=node(3) MATCH v2 = (v1)-->(b)-->(c) RETURN length(v2)

Scalar functions: Type

The rel_type returns a string representation of the relationship type, example:

node(3) > (r = rel) > node; r.rel_type

Generates: START v1=node(3) MATCH (v1)-[?]->(v2) RETURN type(v3)

Scalar function: neo_id

The neo_id method (same name as used in neo4j-core gem) returns the id of the relationship or node.

node(3,4,5).neo_id 

Generates START v1=node(3,4,5) RETURN ID(v1)

Paths

A cypher path is return when using the operators like <<. The path object has the following useful methods:

  • where, example: (node(1) << :person).where{|path| path.nodes.all? { |x| x[:age] > 30 }}.ret(:person)
  • where_not
  • ret
  • all?
  • extract, example (node(1) >> :b >> :c).nodes.extract{ |n| n[:age]}
  • any?
  • none?
  • single?
  • foreach, example: `(node(2) > rel > node(1)).nodes.foreach {|n| n[:marked] = true}
  • shortest_path
  • shortest_paths
  • length

TODO - more docs

Paths, #length

The length of a path can be returned, example:

(node(3) >> :b).length

This is same as START v1=node(3) MATCH v2 = (v1)-->(b) RETURN length(v2)

A more complex example

ret(:a, :b, :c, (node(3).as(:a) > ':KNOWS*0..1' > :b).length, (node(:b) > ':BLOCKS*0..1' > :c).length)

Is same as START a=node(3) MATCH v1 = (a)-[:KNOWS*0..1]->(b),v2 = (b)-[:BLOCKS*0..1]->(c) RETURN a,b,c,length(v1),length(v2)

Clone this wiki locally