Neo4j Cypher 笔记

遇到的问题

修改Label、删除Label、增加Label

neo4j是no-schema的,允许一个节点有0-n个label,也就是可以没有Label,可以有一个Label,也可以有多个

删除Label

match (n) where id(n) = 2 remove n:Label return n;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
neo4j-sh (?)$ match (n) where id(n) = 2 set n:E return id(n), labels(n), n;
+------------------------------------------------+
| id(n) | labels(n) | n |
+------------------------------------------------+
| 2 | ["Person","T","E"] | Node[2]{name:"t"} |
+------------------------------------------------+
1 row
Labels added: 1
136 ms
neo4j-sh (?)$ match (n) where id(n) = 2 remove n:E return id(n), labels(n), n;
+--------------------------------------------+
| id(n) | labels(n) | n |
+--------------------------------------------+
| 2 | ["Person","T"] | Node[2]{name:"t"} |
+--------------------------------------------+
1 row
Labels removed: 1
107 ms
neo4j-sh (?)$ match (n) where id(n) = 2 remove n:Person:T return id(n), labels(n), n;
+---------------------------------------+
| id(n) | labels(n) | n |
+---------------------------------------+
| 2 | [] | Node[2]{name:"t"} |
+---------------------------------------+
1 row
Labels removed: 2
46 ms

可以看到,
第一次操作,原来id=2的节点有3个Label Person、T、E ,移除一个E后,还有2个
第二次操作,原来id=2的节点有2个Label Person、T ,移除两个后,有0个

修改Label

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
neo4j-sh (?)$ match (n) where id(n) = 2 set n:E return id(n), labels(n), n;
+---------------------------------------+
| id(n) | labels(n) | n |
+---------------------------------------+
| 2 | ["E"] | Node[2]{name:"t"} |
+---------------------------------------+
1 row
Labels added: 1
13 ms
neo4j-sh (?)$ match (n) where id(n) = 2 set n:T return id(n), labels(n), n;
+---------------------------------------+
| id(n) | labels(n) | n |
+---------------------------------------+
| 2 | ["T","E"] | Node[2]{name:"t"} |
+---------------------------------------+
1 row
Labels added: 1
29 ms

不remove,直接set,会导致修改完有两个Label,所以需要先remove,然后再set (先set再remove也可以)

1
2


增加Label

neo4j里如何判断一个属性是什么类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE (n {a:1, b:"a", c:[1,2,3]})

MATCH (n)
RETURN size(n.a),
CASE n.a
WHEN toInt(n.a)
THEN 'int'
WHEN toFloat(n.a)
THEN 'float'
WHEN toString(n.a)
THEN 'string'
WHEN [x IN n.a | x]
THEN 'coll'
WHEN NULL THEN 'null'
ELSE 'unknown' END , size(n.b), size(n.c)

how-to-determine-property-value-type-within-a-node-in-neo4j

基本语法

1
2
3
4
5
6
7
8
9

unwind // 把列转为单独的行
// With UNWIND, any list can be transformed back into individual rows.
// The example matches all names from a list of names.


with // 变量传递
// The WITH syntax is similar to RETURN. It separates query parts explicitly,
// allowing you to declare which variables to carry over to the next part.
1
2
3
4
5
6
7
8
9
10
// 查询所有关系的节点的id
match (n)-[r]-(m) with count(r) as count, id(n) as id
where count > 0
return collect(id);

// 查询孤立节点
match (n) where not (n)--() return n;

// 查询孤立节点的所有标签
match (n) where not (n)--() return distinct (labels(n));

Introduction to Cypher

1
2
3
4
5
6
7
8
9
10
11
12
Chapter 3. Introduction to Cypher

Table of Contents
3.1. Background and Motivation
3.2. Graphs, Patterns, and Cypher
3.3. Patterns in Practice
3.4. Getting the Results You Want
3.5. How to Compose Large Statements
3.6. Labels, Constraints and Indexes
3.7. Loading Data
3.8. Utilizing Data Structures
3.9. Cypher vs. SQL

This friendly guide will introduce you to Cypher, Neo4j’s query language.

The guide will help you:

start thinking about graphs and patterns,
apply this knowledge to simple problems,
learn how to write Cypher statements,
use Cypher for loading data,
transition from SQL to Cypher.

If you want to keep a reference at your side while reading, please see the Cypher Refcard.

Background and Motivation

Cypher provides a convenient way to express queries and other Neo4j actions. Although Cypher is particularly useful for exploratory work, it is fast enough to be used in production. Java-based approaches (eg, unmanaged extensions) can also be used to handle particularly demanding use cases.

Query processing

To use Cypher effectively, it’s useful to have an idea of how it works. So, let’s take a high-level look at the way Cypher processes queries.

Parse and validate the query.
Generate the execution plan.
Locate the initial node(s).
Select and traverse relationships.
Change and/or return values.

Preparation

Parsing and validating the Cypher statement(s) is important, but mundane. However, generating an optimal search strategy can be far more challenging.

The execution plan must tell the database how to locate initial node(s), select relationships for traversal, etc. This involves tricky optimization problems (eg, which actions should happen first), but we can safely leave the details to the Neo4j engineers. So, let’s move on to locating the initial node(s).

Locate the initial node(s)

Neo4j is highly optimized for traversing property graphs. Under ideal circumstances, it can traverse millions of nodes and relationships per second, following chains of pointers in the computer’s memory.

However, before traversal can begin, Neo4j must know one or more starting nodes. Unless the user (or, more likely, a client program) can provide this information, Neo4j will have to search for these nodes.

A “brute force” search of the database (eg, for a specified property value) can be very time consuming. Every node must be examined, first to see if it has the property, then to see if the value meets the desired criteria. To avoid this effort, Neo4j creates and uses indexes. So, Neo4j uses a separate index for each label/property combination.

Traversal and actions

Once the initial nodes are determined, Neo4j can traverse portions of the graph and perform any requested actions. The execution plan helps Neo4j to determine which nodes are relevant, which relationships to traverse, etc.

Graphs, Patterns, and Cypher

Nodes, Relationships, and Patterns

Neo4j’s Property Graphs are composed of nodes and relationships, either of which may have properties (ie, attributes). Nodes represent entities (eg, concepts, events, places, things); relationships (which may be directed) connect pairs of nodes.

However, nodes and relationships are simply low-level building blocks. The real strength of the Property Graph lies in its ability to encode patterns of connected nodes and relationships. A single node or relationship typically encodes very little information, but a pattern of nodes and relationships can encode arbitrarily complex ideas.

Cypher, Neo4j’s query language, is strongly based on patterns. Specifically, patterns are used to match desired graph structures. Once a matching structure has been found (or created), Neo4j can use it for further processing.

Simple and Complex Patterns

A simple pattern, which has only a single relationship, connects a pair of nodes (or, occasionally, a node to itself). For example, a Person LIVES_IN a City or a City is PART_OF a Country.

Complex patterns, using multiple relationships, can express arbitrarily complex concepts and support a variety of interesting use cases. For example, we might want to match instances where a Person LIVES_IN a Country. The following Cypher code combines two simple patterns into a (mildly) complex pattern which performs this match:

1
(:Person) -[:LIVES_IN]-> (:City) -[:PART_OF]-> (:Country)

Pattern recognition is fundamental to the way that the brain works. Consequently, humans are very good at working with patterns. When patterns are presented visually (eg, in a diagram or map), humans can use them to recognize, specify, and understand concepts. As a pattern-based language, Cypher takes advantage of this capability.

Cypher Concepts

Like SQL (used in relational databases), Cypher is a textual, declarative query language. It uses a form of ASCII art to represent graph-related patterns. SQL-like clauses and keywords (eg, MATCH, WHERE, DELETE) are used to combine these patterns and specify desired actions.

This combination tells Neo4j which patterns to match and what to do with the matching items (eg, nodes, relationships, paths, collections). However, as a declarative language, Cypher does not tell Neo4j how to find nodes, traverse relationships, etc. (This level of control is available from Neo4j’s Java APIs, see Section 32.2, “Unmanaged Extensions”)

Diagrams made up of icons and arrows are commonly used to visualize graphs; textual annotations provide labels, define properties, etc. Cypher’s ASCII-art syntax formalizes this approach, while adapting it to the limitations of text.

Node Syntax

Cypher uses a pair of parentheses (usually containing a text string) to represent a node, eg: (), (foo). This is reminiscent of a circle or a rectangle with rounded end caps. Here are some ASCII-art encodings for example Neo4j nodes, providing varying types and amounts of detail:

1
2
3
4
5
6
()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: "The Matrix"})
(matrix:Movie {title: "The Matrix", released: 1997})

The simplest form, (), represents an anonymous, uncharacterized node. If we want to refer to the node elsewhere, we can add an identifier, eg: (matrix). Identifiers are restricted (ie, scoped) to a single statement: an identifier may have different (or no) meaning in another statement.

The Movie label (prefixed in use with a colon) declares the node’s type. This restricts the pattern, keeping it from matching (say) a structure with an Actor node in this position. Neo4j’s node indexes also use labels: each index is specific to the combination of a label and a property.

The node’s properties (eg, title) are represented as a list of key/value pairs, enclosed within a pair of braces, eg: {…}. Properties can be used to store information and/or restrict patterns. For example, we could match nodes whose title is “The Matrix”.

Relationship Syntax

Cypher uses a pair of dashes (–) to represent an undirected relationship. Directed relationships have an arrowhead at one end (eg, <–, –>). Bracketed expressions (eg: […]) can be used to add details. This may include identifiers, properties, and/or type information, eg:

1
2
3
4
5
-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ["Neo"]}]->

The syntax and semantics found within a relationship’s bracket pair are very similar to those used between a node’s parentheses. An identifier (eg, role) can be defined, to be used elsewhere in the statement. The relationship’s type (eg, ACTED_IN) is analogous to the node’s label. The properties (eg, roles) are entirely equivalent to node properties. (Note that the value of a property may be an array.)

Pattern Syntax

Combining the syntax for nodes and relationships, we can express patterns. The following could be a simple pattern (or fact) in this domain:

1
2
3
(keanu:Person:Actor {name:  "Keanu Reeves"} )
-[role:ACTED_IN {roles: ["Neo"] } ]->
(matrix:Movie {title: "The Matrix"} )

Like with node labels, the relationship type ACTED_IN is added as a symbol, prefixed with a colon: :ACTED_IN. Identifiers (eg, role) can be used elsewhere in the statement to refer to the relationship. Node and relationship properties use the same notation. In this case, we used an array property for the roles, allowing multiple roles to be specified.
[Note]

Pattern Nodes vs. Database Nodes

When a node is used in a pattern, it describes zero or more nodes in the database. Similarly, each pattern describes zero or more paths of nodes and relationships.
Pattern Identifiers

To increase modularity and reduce repetition, Cypher allows patterns to be assigned to identifiers. This allow the matching paths to be inspected, used in other expressions, etc.

1
acted_in = (:Person)-[:ACTED_IN]->(:Movie)

The acted_in variable would contain two nodes and the connecting relationship for each path that was found or created. There are a number of functions to access details of a path, including nodes(path), rels(path) (same as relationships(path)), and length(path).

Clauses

Cypher statements typically have multiple clauses, each of which performs a specific task, eg:

create and match patterns in the graph
filter, project, sort, or paginate results
connect/compose partial statements

By combining Cypher clauses, we can compose more complex statements that express what we want to know or create. Neo4j then figures out how to achieve the desired goal in an efficient manner.

Neo4j Tutorial

Fundamentals

Store any kind of data using the following graph concepts:

  • Node: Graph data records
  • Relationship: Connect nodes (has direction and a type)
  • Property: Stores data in key-value pair in nodes and relationships
  • Label: Groups nodes and relationships (optional)

Browser editor

CLI

Examples: :help :clear


Cypher

Match

Match node

1
2
3
MATCH (ee:Person)
WHERE ee.name = "Emil"
RETURN ee;
  • MATCH clause to specify a pattern of nodes and relationships
  • (ee:Person) a single node pattern with label ‘Person’ which will assign matches to the variable ee
  • WHERE clause to constrain the results
  • ee.name = “Emil” compares name property to the value “Emil”
  • RETURN clause used to request particular results

Gets gets the id<5> and id<0> nodes and creates a :KNOWS relationship between them

Match nodes and relationships

1
2
3
MATCH (ee:Person)-[:KNOWS]-(friends)
WHERE ee.name = "Emil"
RETURN ee, friends
  • MATCH clause to describe the pattern from known Nodes to found Nodes
  • (ee) starts the pattern with a Person (qualified by WHERE)
  • -[:KNOWS]- matches “KNOWS” relationships (in either direction)
  • (friends) will be bound to Emil’s friends

Match labels

1
2
MATCH (n:Person)
RETURN n

or

1
2
3
MATCH (n)
WHERE n:Person
RETURN n

Match multiple labels

:Car OR :Person labels

1
2
3
MATCH (n)
WHERE n:Person OR n:Car
RETURN n

:Car AND :Person labels

1
2
3
MATCH (n)
WHERE n:Person:Car
RETURN n

Match same properties

1
2
3
MATCH (a:Person)
WHERE a.from = "Sweden"
RETURN a

Returns every node (and their relationships) where there’s a property from with “Sweden” value

Match friends of friends with same hobbies

Johan is learning surfing, and wants to know any friend of his friends who already knows surfing

1
2
3
MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)
WHERE js.name = "Johan" AND surfer.hobby = "surfing"
RETURN DISTINCT surfer
  • () empty parenthesis to ignore these nodes
  • DISTINCT because more than one path will match the pattern
  • surfer will contain Allison, a friend of a friend who surfs

Match by ID

Every node and relationship has an internal autonumeric ID, which can be queried using <, <=, =, =>, <> and IN operators:

Search node by ID

1
2
3
MATCH (n)
WHERE id(n) = 0
RETURN n

Search multiple nodes by ID

1
2
3
MATCH (n)
WHERE id(n) IN [1, 2, 3]
RETURN n

Search relationship by ID

1
2
3
MATCH ()-[n]-()
WHERE id(n) = 0
RETURN n

Create

Create node

1
CREATE (ee:Person { name: "Emil", from: "Sweden", klout: 99 })
  • CREATE clause to create data
  • () parenthesis to indicate a node
  • ee:Person a variable ee and label Person for the new node
  • {} brackets to add properties (key-value pairs) to the node

Create nodes and relationships

1
2
3
4
5
6
7
8
9
MATCH (ee:Person) WHERE ee.name = "Emil"
CREATE (js:Person { name: "Johan", from: "Sweden", learn: "surfing" }),
(ir:Person { name: "Ian", from: "England", title: "author" }),
(rvb:Person { name: "Rik", from: "Belgium", pet: "Orval" }),
(ally:Person { name: "Allison", from: "California", hobby: "surfing" }),
(ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir),
(js)-[:KNOWS]->(ir),(js)-[:KNOWS]->(rvb),
(ir)-[:KNOWS]->(js),(ir)-[:KNOWS]->(ally),
(rvb)-[:KNOWS]->(ally)
  • MATCH clause to get “Emil” in ee variable
  • CREATE clause to create multiple nodes (comma separated) with their labels and properties. Also creates directed relationships (a)-[:Label {key: value}]->(b)

Create relationship between 2 unrelated nodes

1
2
3
MATCH (n), (m)
WHERE n.name = "Allison" AND m.name = "Emil"
CREATE (n)-[:KNOWS]->(m)

Alternative with MERGE, which ensures that the relationship is created only once

1
2
MATCH (n:User {name: "Allison"}), (m:User {name: "Emil"})
MERGE (n)-[:KNOWS]->(m)

Create node with multiple labels

1
CREATE (n:Actor:Director)

Update

Update node properties (add new or modify)

Add new .owns property or modify (if exists)

1
2
3
MATCH (n)
WHERE n.name = "Rik"
SET n.owns = "Audi"

Replace all node properties for the new ones

Danger: It will delete all previous properties and create .plays and .age properties

1
2
3
MATCH (n)
WHERE n.name = "Rik"
SET n = {plays: "Piano", age: 23}

Add new node properties without deleting old ones

Danger: If .plays or .age properties are already set, it will overwrite them

1
2
3
MATCH (n)
WHERE n.name = "Rik"
SET n += {plays: "Piano", age: 23}

Add new node property if property not already set

1
2
3
MATCH (n)
WHERE n.plays = "Guitar" AND NOT (EXISTS (n.likes))
SET n.likes = "Movies"

Rename a property in all nodes

1
2
3
4
MATCH (n)
WHERE NOT (EXISTS (n.instrument))
SET n.instrument = n.plays
REMOVE n.plays

Alternative

1
2
3
4
MATCH (n)
WHERE n.instrument is null
SET n.instrument = n.plays
REMOVE n.plays

Add label to existing node

Adds the :Food label to nodes id<7> and id<8>

1
2
3
MATCH (n)
WHERE id(n) IN [7, 8]
SET n:Food

Creates the node if not exists and updates (or creates) a property

1
2
MERGE (n:Person {name: "Rik"})
SET n.owns = "Audi"

Delete

Delete nodes

To delete a node (p.e. id<5>), first we need to delete its relationships. Then, the node can be deleted

1
2
3
MATCH (n)-[r]-()
WHERE id(n) = 5
DELETE r, n

To delete multiple nodes (must have their relationships previously deleted)

1
2
3
MATCH (n)
WHERE id(n) IN [1, 2, 3]
DELETE n

Deletes a property in a specific node

1
2
3
MATCH (n)
WHERE n:Person AND n.name = "Rik" AND n.plays is NOT null
REMOVE n.plays

Alternative

1
2
3
MATCH (n)
WHERE n:Person AND n.name = "Rik" AND EXISTS (n.plays)
REMOVE n.plays

Delete a label from all nodes

Deletes the :Person label from all nodes

1
2
MATCH (n)
REMOVE n:Person

Delete a label from nodes with specific labels

Deletes the :Person label from nodes with :Food and :Person labels

1
2
3
MATCH (n)
WHERE n:Food:Person
REMOVE n:Person

Delete multiple labels from nodes

Deletes the :Food and :Person labels from nodes which have both labels

1
2
3
MATCH (n)
WHERE n:Food:Person
REMOVE n:Food:Person

Danger: Deletes the :Food and :Person labels from nodes which have :Food or :Person or :Food:Person labels

1
2
MATCH (n)
REMOVE n:Food:Person

Delete entire database

1
2
3
MATCH (n)
OPTIONAL MATCH (n)-[r]-()
DELETE n, r

Other clauses

Show execution plan

Use PROFILE or EXPLAIN before the query

PROFILE: Shows the execution plan, query information and db hits. Example: Cypher version: CYPHER 3.0, planner: COST, runtime: INTERPRETED. 84 total db hits in 32 ms.

EXPLAIN: Shows the execution plan and query information. Example: Cypher version: CYPHER 3.0, planner: COST, runtime: INTERPRETED.

Count

Count all nodes

1
2
MATCH (n)
RETURN count(n)

Count all relationships

1
2
MATCH ()-->()
RETURN count(*);

Limit

Returns up to 2 nodes (and their relationships) where there’s a property from with “Sweden” value

1
2
3
4
MATCH (a:Person)
WHERE a.from = "Sweden"
RETURN a
LIMIT 2

Create unique property constraint

Make .name property unique on nodes with :Person label

1
2
CREATE CONSTRAINT ON (n:Person)
ASSERT n.name IS UNIQUE

Drop unique property constraint

Make .name property unique on nodes with :Person label

1
2
DROP CONSTRAINT ON (n:Person)
ASSERT n.name IS UNIQUE

References

[1] https://neo4j.com/developer/cypher/
[2] https://neo4j.com/docs/cypher-refcard/current/
[3] https://neo4j.com/docs/developer-manual/3.1/cypher/clauses/set/
[4] http://www.jexp.de/blog/html/compiled-runtime-32.html