Neo4j

1. 什么是Neo4j

Neo4j是一个基于图形数据库的开源项目,专门用于存储和查询图形数据。它使用图形结构来表示数据,其中节点表示实体,边表示实体之间的关系。这种结构使得Neo4j非常适合处理复杂的关系数据,如社交网络、推荐系统和知识图谱等。

2. Neo4j的存储方式

Neo4j使用节点,关系,属性来存储数据。
1773984939973

  1. 节点(Node):1773985360393
  • 表示图中的实体,并由标签标记。每个节点可以有一个或多个标签,标签用于分类节点。例如,图中节点标签为"person"和"actor"
  • 节点可以有属性,属性是键值对,用于存储节点的具体信息。例如,一个人的节点可能有属性“name”和“born”。
  • 被索引并受约束
  1. 关系(Relationship):
  • 提供两个节点间的命名链接,必须有起始节点和结束节点。
  • 关系也可以有属性,用于存储关系的具体信息。例如,一个“WORKS_FOR”关系可能有属性“since”,表示某人从什么时候开始在某公司工作。
  • 必须有方向
  • 节点可以拥有多种类型的多个关系。
  1. 属性(Property):
  • 属性是键值对,用于存储节点和关系的具体信息。属性可以是字符串、数字、布尔值等类型。

Cypher查询语言

Cypher是Neo4j的查询语言,类似于SQL,但专门用于图形数据库。它使用模式匹配的方式来查询图形数据,允许用户通过描述图形结构来获取所需的信息。

1. 基本表示法

Cypher最核心的思想是:把图中的结构直接写在查询语句里

  1. 节点用圆括号表示
1
(n)

表示一个节点,n 是变量名,后续可以通过它访问节点属性。

  1. 标签写在节点后面
1
(n:Person)

表示一个标签为 Person 的节点。一个节点可以有多个标签:

1
(n:Person:Student)
  1. 属性写在花括号中
1
(n:Person {name: 'Alice', age: 20})
  1. 关系用方括号表示,箭头表示方向
1
(a)-[r:KNOWS]->(b)

表示 a 通过 KNOWS 关系指向 b。其中:

  • r 是关系变量名
  • KNOWS 是关系类型
  • -> 表示关系方向

如果不关心方向,也可以写成:

1
(a)-[r:KNOWS]-(b)

创建关系时必须指定方向,但查询时可以不指定。

2. 最常用的查询子句

Cypher中最常见的几个子句如下:

  • MATCH:按模式匹配图中的节点和关系
  • WHERE:增加过滤条件
  • RETURN:返回查询结果
  • CREATE:创建节点和关系
  • MERGE:如果不存在就创建,存在就复用
  • SET:修改属性或标签
  • DELETE / DETACH DELETE:删除节点或关系
  • WITH:把前一步结果传递给下一步
  • ORDER BYLIMIT:排序和限制返回数量

一个典型查询的结构通常如下:

1
2
3
4
5
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name = 'Tom Hanks'
RETURN p, m
ORDER BY m.year
LIMIT 10

3. 查询节点

查询所有 Person 节点:

1
2
MATCH (p:Person)
RETURN p

按属性查询:

1
2
MATCH (p:Person {name: 'Alice'})
RETURN p

也可以把条件写在 WHERE 中:

1
2
3
MATCH (p:Person)
WHERE p.age > 18
RETURN p.name, p.age

4. 查询关系和路径

查询某个人认识谁:

1
2
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person)
RETURN b.name

查询两跳关系:

1
2
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->()-[:KNOWS]->(c:Person)
RETURN c.name

查询一条完整路径:

1
2
MATCH path = (a:Person)-[:KNOWS]->(b:Person)
RETURN path

5. 可变长度路径

Cypher可以很方便地表示“走几步关系”。

1
2
MATCH (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b:Person)
RETURN b

这里 *1..3 表示沿着 KNOWS 关系走 1 到 3 步。它常用于:

  • 查找朋友的朋友
  • 查找上下游依赖
  • 查找知识图谱中的多跳关联

6. 创建数据

创建一个节点:

1
2
CREATE (p:Person {name: 'Alice', age: 20})
RETURN p

创建两个节点和它们之间的关系:

1
2
3
CREATE (a:Person {name: 'Alice'})
CREATE (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS]->(b)

也可以一次写完:

1
CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})

7. MERGE:避免重复创建

CREATE 是无条件创建,执行一次就会新增一次数据;MERGE 更像“若不存在则创建”。

1
2
MERGE (p:Person {name: 'Alice'})
RETURN p

创建关系时也常和 MERGE 配合使用:

1
2
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
MERGE (a)-[:KNOWS]->(b)

这是实际使用中非常重要的一个子句,因为知识图谱构建时通常要避免重复节点和重复关系。

8. 修改属性

使用 SET 修改属性:

1
2
3
MATCH (p:Person {name: 'Alice'})
SET p.age = 21
RETURN p

一次设置多个属性:

1
2
3
MATCH (p:Person {name: 'Alice'})
SET p.age = 21, p.city = 'Beijing'
RETURN p

新增标签:

1
2
3
MATCH (p:Person {name: 'Alice'})
SET p:Student
RETURN p

9. 删除数据

删除关系:

1
2
MATCH (:Person {name: 'Alice'})-[r:KNOWS]->(:Person {name: 'Bob'})
DELETE r

删除节点:

1
2
MATCH (p:Person {name: 'Alice'})
DELETE p

如果节点仍然连着关系,直接 DELETE 会失败,此时要用:

1
2
MATCH (p:Person {name: 'Alice'})
DETACH DELETE p

10. 聚合、排序与分页

Cypher支持常见的聚合函数,例如:

  • count()
  • avg()
  • sum()
  • max()
  • min()

例如统计每部电影的演员数量:

1
2
3
4
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
RETURN m.title, count(p) AS actor_count
ORDER BY actor_count DESC
LIMIT 5

11. WITH 的作用

WITH 类似于“中间结果传递”。当查询分成多步时非常有用。

例如先找出演员数量大于 3 的电影,再返回电影名:

1
2
3
4
5
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WITH m, count(p) AS actor_count
WHERE actor_count > 3
RETURN m.title, actor_count
ORDER BY actor_count DESC

12. Cypher 与 SQL 的思维差异

Cypher和SQL都用于查询数据,但思路不同:

  • SQL更关注“表、行、列”
  • Cypher更关注“节点、关系、路径”

在关系数据库中,查询多表关系往往依赖 JOIN;而在图数据库中,关系本身就是一等公民,因此可以直接沿着边进行匹配:

1
2
MATCH (p:Person)-[:WORKS_FOR]->(c:Company)
RETURN p.name, c.name

这也是图数据库特别适合知识图谱、社交网络和推荐系统的原因之一。