1. 简介

Neo4j 是一款高性能的图数据库,使用 Java 语言开发。它将结构化数据存储在网络(图)上而不是传统的表中,使用节点、关系、属性来存储和表示数据,这种数据模型使其能够处理高度互联、关系复杂的数据。

Neo4j 允许将数据库扩展到数十亿个节点,并且可以随时调整图的数据,并在大图中创建深度或广度搜索。

官方网站:https://neo4j.com/

源码地址:https://github.com/neo4j/neo4j

Neo4j 的技术特性:

  • 以图的形式原生存储,而非通过关系表模拟,关系遍历速度比表连接操作更快;
  • 无须预定义模式,可以随时添加新的节点、关系和属性;
  • 使用 Cypher 查询语言来查询和操作图;
  • 支持完整的 ACID 事务;
  • 企业版支持分布式集群部署,提供高可用和水平扩展能力;

图数据库适合用来描述实体之间的关联关系,相比关系型数据库,它能够表达实体之间存在的多种类、更大数据深度的关联关系,同时保持最小的数据规模。

应用场景:

  • 社交网络:分析用户关系,社区发现和影响力分析;
  • 推荐系统:基于用户行为和物品属性的关系,提供个性化推荐;
  • 欺诈检测:分析交易、账户、设备间的关联,识别欺诈和异常;
  • 知识图谱:构建知识网络,用于智能问答和语义搜索;

不适合的场景:

  • 不适合大规模、同质化数据集合的运算;
  • 不适合对数据进行计数、求和、分组等操作;
  • 不适合复杂的事务处理;

2. 概念

2.1 节点

节点(Node)表示图中的实体。

节点有一个或多个标签(Label),表示它在图中的角色。节点的属性(Property)通过任意数量的键值对来表示。

CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})

2.2 关系

关系(Relationship)提供了两个节点之间的连接。

关系是有方向的,具有起始节点、结束节点和关系类型。关系必须具有单一的类型,并且可以有任意个属性。

CREATE ()-[:ACTED_IN {roles: ['Forrest'], performance: 5}]->()

节点之间可以拥有不同类型的多个关系,而不会牺牲性能。

如下图是两个节点及其关系的示意图:

2.3 属性

属性(Property)是若干个键值对,可以用于节点和关系。

// 节点属性
CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})

// 关系属性
CREATE ()-[:ACTED_IN {roles: ['Forrest'], performance: 5}]->()

3. Cypher

Cypher 是 Neo4j 的声明式查询语言,也被称做 CQL。

Cypher 通过圆括号表示节点,通过箭头加方括号表示关系:

(:nodes)-[:relation]->(:otherNodes)

Cypher 包含以下数据类型:

  • boolean:布尔值;
  • byte:8 位整数;
  • short:16 位整数;
  • int:32 位整数;
  • long:64 位整数;
  • float:32 位浮点数;
  • double:64 位浮点数;
  • char:16 位字符;
  • string:字符串;

3.1 概念

节点

节点通常用于表示数据模型中的名词或对象,节点用括号括起来表示,可以通过标签进行分组。

节点名称前有冒号表示一个类型,而没有冒号则表示一个变量。

// John 变量
(John)
 
// Person 类型,并且包含标签
(:Person{name:"John"})

节点可以绑定到变量中,以在后续子句引用匹配的数据实体。如下将标记为 Person 的节点绑定到变量 p,以在下文中引用:

MATCH (p:Person)
RETURN p

关系

关系可以存储节点之间的关联信息,表示为方括号和连接两个节点的箭头。

(Node1)-[]→(Node2)

关系名称前有冒号表示一个类型,而没有冒号则表示一个变量。

// LIKE 变量
(:Person)-[LIKE]→(:Technology)

// LIKE 类型
(:Person)-[:LIKE]→(:Technology)

关系总是有方向的,未指定方向的关系可以从两个方向遍历。

// 从左到右
(p:Person)-[:LIKES]->(t:Technology)

// 从右到左
(p:Person)<-[:LIKES]-(t:Technology)

// 未指定方向
MATCH (p:Person)-[:LIKES]-(t:Technology)

关系的类型类似于分组标签,一般是使用动词作为关系的类型,而节点则使用名次,可以很自然地表示现实中的关系。类型必须写在冒号后面,如果没有冒号就是变量。

// LIKES是类型
MATCH (p:Person)-[:LIKES]-(t:Technology)

// LIKES是变量
MATCH (p:Person)-[LIKES]-(t:Technology)

关系变量则用于在查询的稍后引用它。

// r是变量,LIKES是类型
MATCH (p:Person)-[r:LIKES]->(t:Technology)
RETURN p,r,t

属性

节点和关系中可以添加一到多个属性,以键值对的形式存在。

CREATE (p:Person {name:'Sally'})-[r:IS_FRIENDS_WITH]->(p:Person {name:'John'})
RETURN p, r

模式和语句

模式是用来声明关系的,需要通过 CREATE 子句将信息添加到数据库,然后通过 MATCH 来用模式检索数据。

// 模式
(p:Person {name: "Sally"})-[r:LIKES]->(t:Technology {type: "Graphs"})

// 插入
CREATE (p:Person {name: "Sally"})-[r:LIKES]->(t:Technology {type: "Graphs"})

// 检索
MATCH (p:Person {name: "Sally"})-[r:LIKES]->(t:Technology {type: "Graphs"})
RETURN p,r,t

3.2 语句

创建

CREATE 用于创建节点和关系。

// 创建节点
CREATE (p:Person)

// 创建节点,带有多种标签
CREATE (p:Person:Employee)

// 创建节点并带有属性
CREATE (p:Person{name:"John"})

// 创建关系
CREATE (p:Person {name:'Sally'})-[r:IS_FRIENDS_WITH]->(p:Person {name:'John'})

MERGE 先查询节点和关系是否存在,存在则返回,不存在则创建。

MERGE (p:Person{name:"John"})

SET 用于向节点和关系添加或设置属性。

// 添加属性
MATCH (p:Person{id:123})
SET p.age=30

查询

MATCH 用于查询节点和关系。

RETURN 用于返回查询的内容。

WHERE 用于过滤查询结果,通过比较运算符 =、<>、<、>、<=、>=、IS NULL、IS NOT NULL、IN、=~(正则表达式匹配)来比较结果,通过布尔运算符 AND、OR、NOT、XOR 来支持多个条件。

// 查询某种标签的节点
MATCH (p:Person)
RETURN p

// 查询并返回属性
MATCH (p:Person)
RETURN p.name,p.age

// 查询并指定条件
MATCH (p:Person)
WHERE p.name <> 'Tom' AND p.age < 30
RETURN p

// 查询并根据结果创建关系
MATCH (p1:Person),(p2.Person)
WHERE p1.id = 123 AND p2.id = 200
CREATE (p1)-[r:BORROW{date:"20260301",price:1000}]->(p2)
RETURN r

ORDER BY用于对查询结果进行排序,默认升序,可以添加 DESC 指定降序。

// 排序
MATCH (p:Person)
RETURN p.name,p.age
ORDER BY p.age

LIMIT 用于限制返回的行数。

SKIP 用于跳过返回的行数。

// 限制返回行数
MATCH (p:Person)
RETURN p
LIMIT 10

// 跳过返回行数
MATCH (p:Person)
RETURN p
SKIP 30

// 获取指定分页的行数
MATCH (p:Person)
RETURN p
SKIP 30 LIMIT 10

以上子句的顺序为 MATCH - WHERE - RETURN - ORDER BY - SKIP - LIMIT。

UNION 和 UNION ALL 将多个子句的结果合并为一组,前者去除重复行,后者保留重复行。

// 合并结果,去除重复
MATCH (p:Person) RETURN p.name,p.age
UNION
MATCH (e:Employee) RETURN e.name,e.age

// 合并结果,保留重复
MATCH (p:Person) RETURN p.name,p.age
UNION ALL
MATCH (e:Employee) RETURN e.name,e.age

删除

DELETE 用于删除节点和关系。

// 删除某一标签的节点
MATCH (p:Person)
DELETE p

// 删除关系
MATCH (p:Person)-[r]-(p:Person)
DELETE r

REMOVE 用于删除标签和属性。

// 删除属性
MATCH (p:Person)
REMOVE p.age

// 删除标签
MATCH (p:Person)
REMOVE p.Employee

3.3 函数

字符串函数

UPPER 函数将字符串转为大写字母。

MATCH (p:Person)
RETURN UPPER(p.name)

UPPER 函数将字符串转为小写字母。

MATCH (p:Person)
RETURN LOWER(p.name)

STARTS WITH 函数判断字符串前缀,ENDS WITH 函数判断字符串后缀,CONTAINS 函数判断字符串包含子串。

MATCH (p:Person)
WHERE p.name STARTS WITH "Com" OR p.name ENDS WITH "." OR p.name CONTAINS "-"
RETURN p.name

SUBSTRING 函数获取字符串的子串,需要指定开始和结束的索引下标。

MATCH (p:Person)
RETURN LOWER(p.name,0,10)

REPLACE 函数替换字符串的指定内容,指定搜索的子串和替换的内容。

MATCH (p:Person)
RETURN REPLACE(p.name,"old","new")

聚合函数

COUNT 函数返回行数。

MAX 函数返回最大值,MIN 函数返回最小值。

AVG 函数返回平均值,SUM 函数返回求和值。

MATCH (p:Person)
RETURN COUNT(*),MAX(p.age),MIN(p.age),AVG(p.salary),SUM(p.salary)

COLLECT 函数用于将聚合属性外的其他属性以列表列出。

SIZE 函数用于计算列表的大小。

MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
RETURN m.title AS movie, COLLECT(a.name) AS cast, SIZE(COLLECT(a.name)) AS cast_number, COUNT(*) AS actors

UNWIND 函数将指定列表分解为多个单独的值,用来匹配节点或关系的属性。

// 匹配节点
WITH [4, 5, 6, 7] AS experienceRange
UNWIND experienceRange AS number
MATCH (p:Person)
WHERE p.yearsExp = number
RETURN p.name, p.yearsExp

// 匹配关系
WITH ['Graphs','Query Languages'] AS techRequirements
UNWIND techRequirements AS technology
MATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})
RETURN t.type, collect(p.name) AS potentialCandidates

关系函数

STARTNODE 函数获取关系的开始节点,ENDNODE 函数获取关系的结束节点。

MATCH (a)-[movie:ACTION_MOVIES]->(b) 
RETURN STARTNODE(movie),ENDNODE(movie)

ID 函数获取关系的 ID,TYPE 函数获取关系的类型。

MATCH (a)-[movie:ACTION_MOVIES]->(b) 
RETURN ID(movie),TYPE(movie)

3.4 索引

为某类节点的特定属性创建索引,以加速查询。

CREATE INDEX ON :Person (name)

CREATE INDEX Person_name IF NOT EXISTS FOR (p:Person) ON p.name

删除已有索引。

DROP INDEX ON :Person (name)

3.5 约束

创建 UNIQUE 约束用来避免指定的属性产生相同的值。

CREATE CONSTRAINT ON (p:Person)
ASSERT p.name IS UNIQUE

删除已有约束。

DROP CONSTRAINT ON (p:Person)
ASSERT p.name IS UNIQUE

4. 参考