第4章:Cypher查询语言基础
Cypher是Neo4j的声明式图查询语言,专为处理图数据而设计。它允许用户以直观、高效的方式查询和修改图数据库中的数据。本章将介绍Cypher的基本概念和语法,帮助读者掌握使用Cypher进行基础图数据操作的能力。
4.1 Cypher语言概述
Cypher是Neo4j的主要查询语言,其设计理念是让图查询变得简单直观,即使对于没有编程背景的用户也能快速上手。了解Cypher的设计理念和基本语法结构,是掌握这门语言的第一步。
Cypher的设计理念
Cypher 的设计融合了 SQL、SPARQL 和正则表达式等多种语言和概念,其核心理念体现在声明式查询、模式匹配、可读性和灵活性等方面。首先,Cypher 是一种声明式语言,用户只需描述“想要什么”,而无需关心“如何获取”,这让查询更专注于业务需求而非实现细节。其次,Cypher 以模式匹配为核心,用户通过描述节点和关系的结构,Neo4j 引擎自动查找匹配的子图。Cypher 独特的 ASCII 艺术风格语法,使节点和关系的结构在查询语句中直观可见,提升了可读性。其语法接近自然语言,即使复杂查询也能简洁表达,便于理解和维护。此外,Cypher 支持通过组合简单模式构建复杂查询,实现查询的模块化和重用。灵活的查询能力涵盖从精确匹配到路径分析和聚合操作等多种场景。这些设计理念共同造就了 Cypher 强大且易用的特性,适用于各种图数据检索与分析需求。
Cypher与SQL的对比
对于熟悉SQL的用户,了解Cypher与SQL的异同有助于快速掌握这门新语言。
Cypher和SQL都是声明式查询语言,用户只需描述“想要什么”,而无需关心“如何获取”。两者都采用类似的子句结构,例如Cypher的MATCH
与SQL的SELECT
,以及共同的WHERE
、ORDER BY
等子句。此外,它们都支持聚合函数和分组操作,能够对数据进行统计和汇总。无论是Cypher还是SQL,都具备事务支持和数据修改语句,能够保证数据操作的完整性和一致性。
Cypher与SQL的主要区别体现在数据模型、连接方式、关系查询、结果形式和语法风格等方面。首先,SQL采用表格模型,数据以行和列的形式组织,而Cypher则基于图模型,数据以节点、关系和属性的方式存储。其次,在连接操作上,SQL通过JOIN语句实现表之间的关联,而Cypher则通过模式匹配和路径表达式直接描述节点之间的连接。对于复杂关系的查询,SQL需要多个JOIN操作,随着关系层级的增加,查询语句会变得更加复杂;而Cypher可以用简洁的路径表达式(如()-[:KNOWS*1..3]->()
)直接表示和查询任意深度的关系。查询结果方面,SQL通常返回表格数据(行和列),而Cypher不仅可以返回表格,还能返回路径或子图,更适合图结构的数据分析。最后,语法风格上,SQL以英语关键词和表达式为主,Cypher则结合了英语关键词和ASCII艺术风格的图模式,使查询结构更加直观和易读。
以下是一个简单的对比示例,展示了如何使用Cypher和SQL查询图数据。
查找名为"John"的用户的朋友:
SQL(假设有Users表和Friendships表):
SELECT f.name
FROM Users u
JOIN Friendships fs ON u.id = fs.user_id
JOIN Users f ON fs.friend_id = f.id
WHERE u.name = 'John';
Cypher:
MATCH (u:User {name: 'John'})-[:FRIENDS_WITH]->(f:User)
RETURN f.name;
查找朋友的朋友:
SQL:
SELECT ff.name
FROM Users u
JOIN Friendships fs1 ON u.id = fs1.user_id
JOIN Users f ON fs1.friend_id = f.id
JOIN Friendships fs2 ON f.id = fs2.user_id
JOIN Users ff ON fs2.friend_id = ff.id
WHERE u.name = 'John'
AND ff.id <> u.id; -- 排除自己
Cypher:
MATCH (u:User {name: 'John'})-[:FRIENDS_WITH]->(f:User)-[:FRIENDS_WITH]->(ff:User)
WHERE u <> ff -- 排除自己
RETURN ff.name;
这种对比清晰地展示了Cypher在处理关联数据时的简洁性和直观性。随着关系复杂度的增加,这种优势会变得更加明显。
Cypher的语法结构
Cypher查询语句由多个子句组成,每个子句负责查询的不同方面。理解这些基本子句及其组合方式是掌握Cypher的基础。
主要子句及其功能:
-
MATCH:指定要在图中查找的模式。这是大多数Cypher查询的起点。
MATCH (p:Person)-[:WORKS_FOR]->(c:Company)
-
WHERE:添加过滤条件,限制匹配结果。
WHERE p.age > 30 AND c.name = 'Neo4j'
-
RETURN:指定查询结果中应包含哪些数据。
RETURN p.name, p.age, c.name
-
ORDER BY:对结果进行排序。
ORDER BY p.age DESC
-
SKIP/LIMIT:分页或限制结果数量。
SKIP 10 LIMIT 5
-
CREATE:创建新的节点或关系。
CREATE (p:Person {name: 'Alice', age: 30})
-
MERGE:查找现有模式,如果不存在则创建。
MERGE (p:Person {name: 'Bob'})
-
SET:设置或更新属性。
SET p.age = 31
-
DELETE/DETACH DELETE:删除节点或关系。
DETACH DELETE p
-
WITH:将一个查询部分的结果传递给下一个部分,允许查询链接。
MATCH (p:Person) WITH p, size((p)-[:KNOWS]->()) AS friendCount WHERE friendCount > 5 RETURN p.name, friendCount
Cypher语句的基本结构通常遵循这样的模式:
- 使用
MATCH
找到图中的模式 - 使用
WHERE
应用过滤条件 - 使用
RETURN
指定输出 - 可选地使用
ORDER BY
、SKIP
、LIMIT
等修饰结果
更复杂的查询可能包括:
- 多个
MATCH
子句 - 使用
WITH
连接的多个查询部分 - 子查询和复合查询
- 聚合和分组操作
节点和关系的表示:
- 节点用圆括号表示:
()
- 可以为节点指定变量名:
(p)
- 可以为节点指定标签:
(p:Person)
- 可以为节点指定属性:
(p:Person {name: 'Alice'})
- 关系用方括号表示,并用箭头指示方向:
-[:KNOWS]->
- 可以为关系指定变量名:
-[r:KNOWS]->
- 可以为关系指定属性:
-[r:KNOWS {since: 2020}]->
- 可以指定关系的方向,或者不指定方向(双向):
-[:KNOWS]->
,<-[:KNOWS]-
,-[:KNOWS]-
路径变量:
可以为整个路径指定一个变量,以便后续引用:
MATCH p = (a:Person)-[:KNOWS]->(b:Person)
RETURN p
理解这些基本语法元素及其组合方式,是掌握Cypher的关键。随着经验的积累,您将能够编写越来越复杂和强大的查询。
4.2 基本查询操作
掌握基本的查询操作是使用Cypher的第一步。本节将介绍如何使用MATCH、WHERE、RETURN等子句进行基本的数据检索。
MATCH与WHERE子句
MATCH
子句是Cypher查询的核心,用于指定要在图中查找的模式。WHERE
子句则用于添加过滤条件,进一步限定匹配结果。
基本的MATCH用法:
-
匹配特定标签的节点:
MATCH (p:Person) RETURN p
这将返回所有带有
Person
标签的节点。 -
匹配多个标签:
MATCH (p:Person:Employee) RETURN p
这将返回同时带有
Person
和Employee
标签的节点。 -
匹配特定属性的节点:
MATCH (p:Person {name: 'Alice'}) RETURN p
这将返回标签为
Person
且name
属性值为’Alice’的节点。 -
匹配关系:
MATCH (p:Person)-[:KNOWS]->(friend) RETURN p, friend
这将返回所有
Person
节点及其通过KNOWS
关系连接的朋友节点。 -
匹配多跳关系:
MATCH (p:Person)-[:KNOWS*1..3]->(friend) RETURN p, friend
这将返回与
Person
节点之间有1到3跳KNOWS
关系的朋友节点。
WHERE子句的使用:
-
基本比较:
MATCH (p:Person) WHERE p.age > 30 RETURN p
返回年龄大于30的所有
Person
节点。 -
多条件过滤:
MATCH (p:Person) WHERE p.age > 30 AND p.city = 'London' RETURN p
返回年龄大于30且城市为London的所有
Person
节点。 -
字符串操作:
MATCH (p:Person) WHERE p.name STARTS WITH 'A' RETURN p
返回名字以’A’开头的所有
Person
节点。 -
正则表达式:
MATCH (p:Person) WHERE p.email =~ '.*@gmail\\.com' RETURN p
返回Gmail邮箱的所有
Person
节点。 -
列表操作:
MATCH (p:Person) WHERE 'Java' IN p.skills RETURN p
返回技能列表中包含’Java’的所有
Person
节点。 -
存在性检查:
MATCH (p:Person) WHERE exists(p.phone) RETURN p
返回有
phone
属性的所有Person
节点。 -
路径过滤:
MATCH (p:Person)-[r:RATED]->(m:Movie) WHERE r.score > 4 RETURN p, m
返回评分高于4的所有人-电影对。
MATCH和WHERE的组合使用允许构建复杂的查询模式和过滤条件,是Cypher查询的基础。
RETURN与ORDER BY子句
RETURN
子句指定查询结果中应包含哪些数据,而ORDER BY
子句则用于对结果进行排序。
RETURN子句的用法:
-
返回整个节点或关系:
MATCH (p:Person) RETURN p
返回完整的
Person
节点,包括所有属性。 -
返回特定属性:
MATCH (p:Person) RETURN p.name, p.age
只返回
Person
节点的name
和age
属性。 -
使用别名:
MATCH (p:Person) RETURN p.name AS Name, p.age AS Age
为返回的属性指定别名,使结果更易读。
-
返回计算结果:
MATCH (p:Person) RETURN p.name, p.birthYear, 2023 - p.birthYear AS Age
返回计算得出的年龄。
-
返回去重结果:
MATCH (p:Person)-[:LIVES_IN]->(c:City) RETURN DISTINCT c.name
返回不重复的城市名称。
-
返回聚合结果:
MATCH (p:Person) RETURN count(p) AS PersonCount, avg(p.age) AS AvgAge
返回人数统计和平均年龄。
ORDER BY子句的用法:
-
基本排序:
MATCH (p:Person) RETURN p.name, p.age ORDER BY p.age
按年龄升序排列结果。
-
指定排序方向:
MATCH (p:Person) RETURN p.name, p.age ORDER BY p.age DESC
按年龄降序排列结果。
-
多字段排序:
MATCH (p:Person) RETURN p.name, p.age, p.city ORDER BY p.city, p.age DESC
先按城市升序排列,城市相同的再按年龄降序排列。
-
使用表达式排序:
MATCH (p:Person)-[:KNOWS]->(friend) RETURN p.name, count(friend) AS FriendCount ORDER BY FriendCount DESC
按朋友数量降序排列。
-
使用别名排序:
MATCH (p:Person) RETURN p.name AS Name, p.age AS Age ORDER BY Age
使用返回结果的别名进行排序。
RETURN
和ORDER BY
子句的灵活使用,可以帮助您获取所需的数据并以合适的方式呈现。
LIMIT与SKIP子句
LIMIT
和SKIP
子句用于控制返回结果的数量和起始位置,常用于分页查询。
LIMIT子句限制返回的结果数量:
MATCH (p:Person)
RETURN p.name, p.age
LIMIT 10
这将只返回前10个结果。
SKIP子句跳过指定数量的结果:
MATCH (p:Person)
RETURN p.name, p.age
SKIP 10
这将跳过前10个结果,从第11个开始返回。
组合使用实现分页:
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.name
SKIP 20 LIMIT 10
这将返回按名字排序后的第21到第30个结果,相当于第3页(假设每页10条)。
注意事项:
- 使用
SKIP
和LIMIT
进行分页时,应始终配合ORDER BY
使用,以确保分页结果的一致性。 - 对于大数据集,大的
SKIP
值可能导致性能问题,因为Neo4j需要先找到所有匹配的结果,然后跳过指定数量。在这种情况下,可以考虑使用其他分页策略,如基于上一页最后一个结果的属性值进行过滤。
基础查询模式
掌握一些常见的查询模式,可以帮助您更有效地使用Cypher。以下是一些基础查询模式:
-
查找与特定节点相关的节点:
MATCH (p:Person {name: 'Alice'})-[:KNOWS]->(friend) RETURN friend.name
查找Alice认识的所有人。
-
查找两个节点之间的关系:
MATCH (p1:Person {name: 'Alice'})-[r]-(p2:Person {name: 'Bob'}) RETURN type(r), r
查找Alice和Bob之间的所有关系。
-
查找满足特定条件的路径:
MATCH path = (start:Person {name: 'Alice'})-[:KNOWS*1..3]-(end:Person {name: 'Charlie'}) RETURN path
查找Alice和Charlie之间最多3跳的"认识"路径。
-
查找没有特定关系的节点:
MATCH (p:Person) WHERE NOT (p)-[:LIVES_IN]->() RETURN p.name
查找没有指定居住地的人。
-
查找具有最多关系的节点:
MATCH (p:Person)-[:KNOWS]->(friend) RETURN p.name, count(friend) AS FriendCount ORDER BY FriendCount DESC LIMIT 5
查找朋友最多的5个人。
-
查找共同关系:
MATCH (p1:Person {name: 'Alice'})-[:KNOWS]->(common)<-[:KNOWS]-(p2:Person {name: 'Bob'}) RETURN common.name
查找Alice和Bob共同认识的人。
-
条件路径查询:
MATCH (p:Person {name: 'Alice'})-[:KNOWS]->(friend) WHERE friend.age > 30 RETURN friend.name, friend.age
查找Alice认识的年龄大于30岁的朋友。
-
组合多个MATCH子句:
MATCH (p:Person {name: 'Alice'}) MATCH (p)-[:LIVES_IN]->(city) MATCH (other:Person)-[:LIVES_IN]->(city) WHERE other <> p RETURN other.name AS Neighbor, city.name AS City
查找与Alice住在同一城市的其他人。
这些基础查询模式可以根据具体需求进行调整和组合,构建更复杂的查询。随着对Cypher的深入理解,您将能够设计出更高效、更精确的查询来满足各种业务需求。
4.3 创建与修改操作
除了查询数据,Cypher还提供了强大的数据创建和修改功能。本节将介绍如何使用CREATE、MERGE、SET等命令来添加和更新图数据。
CREATE与MERGE命令
CREATE
命令用于在图中创建新的节点和关系,而MERGE
命令则结合了查找和创建功能,只在不存在时才创建新的元素。
CREATE命令的用法:
-
创建单个节点:
CREATE (p:Person {name: 'Alice', age: 30})
创建一个带有
Person
标签和两个属性的节点。 -
创建多个节点:
CREATE (p1:Person {name: 'Alice', age: 30}),(p2:Person {name: 'Bob', age: 35})
一次创建多个节点。
-
创建节点和关系:
CREATE (p1:Person {name: 'Alice'})-[:KNOWS {since: 2020}]->(p2:Person {name: 'Bob'})
创建两个节点及它们之间的关系。
-
创建关系(节点已存在):
MATCH (p1:Person {name: 'Alice'}), (p2:Person {name: 'Bob'}) CREATE (p1)-[:KNOWS {since: 2020}]->(p2)
在已存在的节点之间创建关系。
MERGE命令的用法:
-
合并节点:
MERGE (p:Person {name: 'Alice'}) ON CREATE SET p.created = timestamp() ON MATCH SET p.lastSeen = timestamp()
如果不存在名为’Alice’的
Person
节点,则创建一个并设置created
属性;如果已存在,则更新lastSeen
属性。 -
合并关系:
MATCH (p1:Person {name: 'Alice'}), (p2:Person {name: 'Bob'}) MERGE (p1)-[r:KNOWS]->(p2) ON CREATE SET r.since = 2020
如果Alice和Bob之间不存在
KNOWS
关系,则创建一个并设置since
属性。 -
合并完整路径:
MERGE (p1:Person {name: 'Alice'})-[r:KNOWS]->(p2:Person {name: 'Bob'})
这将确保整个路径存在,如果任何部分(节点或关系)不存在,则创建它。
CREATE与MERGE的区别:
CREATE
总是创建新的节点或关系,即使完全相同的已经存在。MERGE
首先尝试查找匹配的模式,只有在不存在时才创建新的元素。- 使用
MERGE
时,可以使用ON CREATE
和ON MATCH
子句分别处理创建和匹配的情况。
使用建议:
- 当确定要创建新元素且不关心重复时,使用
CREATE
。 - 当需要确保唯一性或实现"查找或创建"逻辑时,使用
MERGE
。 - 对于大批量数据导入,
CREATE
通常比MERGE
更高效,因为它不需要先查找。
SET与REMOVE命令
SET
命令用于添加或更新节点和关系的属性或标签,而REMOVE
命令用于删除属性或标签。
SET命令的用法:
-
设置或更新单个属性:
MATCH (p:Person {name: 'Alice'}) SET p.age = 31
将Alice的年龄更新为31。
-
同时设置多个属性:
MATCH (p:Person {name: 'Alice'}) SET p.age = 31, p.updated = timestamp()
同时更新多个属性。
-
使用属性映射设置多个属性:
MATCH (p:Person {name: 'Alice'}) SET p += {age: 31, city: 'London', updated: timestamp()}
使用映射一次性设置多个属性。
-
添加标签:
MATCH (p:Person {name: 'Alice'}) SET p:Employee
给节点添加新的标签。
-
替换所有属性:
MATCH (p:Person {name: 'Alice'}) SET p = {name: 'Alice', age: 31, city: 'London'}
这将替换节点的所有现有属性。注意:这会删除未在新映射中指定的任何属性。
REMOVE命令的用法:
-
删除属性:
MATCH (p:Person {name: 'Alice'}) REMOVE p.age
删除Alice的年龄属性。
-
删除多个属性:
MATCH (p:Person {name: 'Alice'}) REMOVE p.age, p.city
同时删除多个属性。
-
删除标签:
MATCH (p:Person:Temporary {name: 'Alice'}) REMOVE p:Temporary
删除节点的
Temporary
标签。
SET与REMOVE的注意事项:
SET
可以添加新属性或覆盖现有属性,但不会删除未提及的属性。- 使用
SET p = {...}
会替换所有现有属性,可能导致数据丢失。 REMOVE
永久删除属性或标签,无法撤销。- 删除节点的最后一个标签不会删除节点本身。
- 属性值可以设置为
null
,但这与删除属性不同。设置为null
的属性仍然存在,只是值为null
。
DELETE与DETACH DELETE命令
DELETE
命令用于删除节点和关系,而DETACH DELETE
命令用于删除节点及其所有关系。
DELETE命令的用法:
-
删除关系:
MATCH (p1:Person {name: 'Alice'})-[r:KNOWS]->(p2:Person {name: 'Bob'}) DELETE r
删除Alice和Bob之间的
KNOWS
关系。 -
删除没有关系的节点:
MATCH (p:Person {name: 'Charlie'}) WHERE NOT (p)--() // 确保节点没有关系 DELETE p
删除没有任何关系的Charlie节点。
DETACH DELETE命令的用法:
-
删除节点及其所有关系:
MATCH (p:Person {name: 'Alice'}) DETACH DELETE p
删除Alice节点及其所有入站和出站关系。
-
删除多个节点及其关系:
MATCH (p:Person) WHERE p.inactive = true DETACH DELETE p
删除所有标记为非活跃的人及其关系。
DELETE与DETACH DELETE的注意事项:
- 尝试删除仍有关系的节点(不使用
DETACH
)会导致错误。 DETACH DELETE
是一个强大的操作,会删除节点的所有关系,使用时需谨慎。- 删除操作是永久性的,无法撤销。在生产环境中执行删除操作前,建议先进行备份或使用测试数据库。
- 可以在一个事务中组合多个操作,例如先创建新节点,然后删除旧节点。
基础修改模式
以下是一些常见的数据修改模式,展示了如何组合使用上述命令来完成常见任务:
-
创建唯一节点:
MERGE (p:Person {email: 'alice@example.com'}) ON CREATE SET p.name = 'Alice', p.created = timestamp()
确保每个电子邮件只对应一个
Person
节点。 -
添加关系(如果不存在):
MATCH (p1:Person {name: 'Alice'}), (p2:Person {name: 'Bob'}) MERGE (p1)-[r:KNOWS]->(p2) ON CREATE SET r.since = date()
确保Alice和Bob之间有一个
KNOWS
关系。 -
更新或创建节点和关系:
MERGE (p:Person {email: 'alice@example.com'}) ON CREATE SET p.name = 'Alice', p.created = timestamp() ON MATCH SET p.lastSeen = timestamp() WITH p MATCH (c:Company {name: 'Neo4j'}) MERGE (p)-[r:WORKS_FOR]->(c) ON CREATE SET r.since = date()
确保用户存在并与公司有工作关系。
-
条件更新:
MATCH (p:Person {name: 'Alice'}) SET p.age = CASE WHEN p.age IS NULL THEN 30 ELSE p.age + 1 END
如果年龄未设置,则设为30;否则增加1。
-
批量更新:
MATCH (p:Person) WHERE p.city = 'New York' SET p.region = 'East Coast'
为所有纽约的人设置区域属性。
-
替换节点:
MATCH (old:Person {name: 'Alice', outdated: true}) CREATE (new:Person {name: 'Alice', updated: true}) WITH old, new MATCH (old)-[r]->(other) CREATE (new)-[r2:KNOWS]->(other) SET r2 = properties(r) WITH old, new MATCH (other)-[r]->(old) CREATE (other)-[r2:KNOWS]->(new) SET r2 = properties(r) WITH old DETACH DELETE old
创建节点的新版本,复制所有关系,然后删除旧节点。
-
有条件地删除数据:
MATCH (p:Person)-[r:VISITED]->(c:City) WHERE r.lastVisit < date('2020-01-01') DELETE r
删除2020年之前的访问记录。
这些基础修改模式展示了Cypher在数据操作方面的灵活性和表达能力。通过组合不同的命令和子句,可以实现各种复杂的数据修改需求。
4.4 基础查询模式
在实际应用中,某些查询模式会反复出现。掌握这些常见的查询模式,可以帮助您更有效地使用Cypher解决实际问题。
节点查询模式
节点查询是最基本的查询类型,涉及查找和过滤特定类型的节点。
-
基于标签查询:
MATCH (p:Person) RETURN p
查找所有
Person
节点。 -
基于属性查询:
MATCH (p:Person {name: 'Alice'}) RETURN p
查找名为’Alice’的
Person
节点。 -
使用WHERE子句的复杂过滤:
MATCH (p:Person) WHERE p.age > 30 AND p.city = 'London' RETURN p
查找年龄大于30且住在伦敦的人。
-
模糊查询:
MATCH (p:Person) WHERE p.name CONTAINS 'Al' OR p.name STARTS WITH 'B' RETURN p
查找名字包含’Al’或以’B’开头的人。
-
正则表达式查询:
MATCH (p:Person) WHERE p.email =~ '.*@gmail\\.com' RETURN p
查找使用Gmail的人。
-
空值处理:
MATCH (p:Person) WHERE p.age IS NULL RETURN p
查找未设置年龄的人。
-
列表属性查询:
MATCH (p:Person) WHERE 'Java' IN p.skills RETURN p
查找技能包含’Java’的人。
-
计算属性查询:
MATCH (p:Person) WHERE size(p.name) > 5 RETURN p
查找名字长度大于5的人。
关系查询模式
关系查询涉及查找节点之间的连接和路径。
-
基本关系查询:
MATCH (p:Person)-[:KNOWS]->(friend) RETURN p.name, friend.name
查找所有人及其认识的朋友。
-
特定关系查询:
MATCH (p:Person {name: 'Alice'})-[:KNOWS]->(friend) RETURN friend.name
查找Alice认识的所有人。
-
关系属性过滤:
MATCH (p:Person)-[r:KNOWS]->(friend) WHERE r.since > 2018 RETURN p.name, friend.name, r.since
查找2018年之后建立的朋友关系。
-
多重关系查询:
MATCH (p:Person)-[:KNOWS|:WORKS_WITH]->(other) RETURN p.name, other.name
查找通过’认识’或’一起工作’关系连接的人。
-
关系方向不限:
MATCH (p:Person {name: 'Alice'})-[:KNOWS]-(friend) RETURN friend.name
查找与Alice互相认识的人(不考虑关系方向)。
-
关系类型动态查询:
MATCH (p:Person {name: 'Alice'})-[r]->(other) RETURN type(r), other.name
查找Alice与其他节点之间的所有关系类型。
-
关系计数:
MATCH (p:Person) RETURN p.name, size((p)-[:KNOWS]->()) AS FriendCount
统计每个人的朋友数量。
路径查询模式
路径查询涉及查找节点之间的连接路径,可能跨越多个关系。
-
固定长度路径:
MATCH (p1:Person {name: 'Alice'})-[:KNOWS]->(friend)-[:KNOWS]->(foaf) RETURN foaf.name
查找Alice的朋友的朋友。
-
可变长度路径:
MATCH (p1:Person {name: 'Alice'})-[:KNOWS*1..3]->(other) RETURN other.name
查找与Alice距离1到3跳的所有人。
-
最短路径:
MATCH p = shortestPath((p1:Person {name: 'Alice'})-[:KNOWS*]-(p2:Person {name: 'Charlie'})) RETURN length(p), [n IN nodes(p) | n.name]
查找Alice和Charlie之间的最短路径。
-
所有简单路径:
MATCH p = allShortestPaths((p1:Person {name: 'Alice'})-[:KNOWS*]-(p2:Person {name: 'Charlie'})) RETURN p
查找Alice和Charlie之间的所有最短路径。
-
带条件的路径查询:
MATCH path = (p1:Person {name: 'Alice'})-[:KNOWS*1..3]->(p2:Person) WHERE all(r IN relationships(path) WHERE r.active = true) RETURN p2.name
查找通过所有活跃关系连接的人。
-
路径不包含特定节点:
MATCH path = (p1:Person {name: 'Alice'})-[:KNOWS*1..3]->(p2:Person {name: 'Charlie'}) WHERE none(n IN nodes(path) WHERE n.name = 'Bob') RETURN path
查找不经过Bob的从Alice到Charlie的路径。
-
带权重的路径查询:
MATCH path = (p1:Person {name: 'Alice'})-[:KNOWS*1..3]->(p2:Person) RETURN p2.name, reduce(weight = 0, r IN relationships(path) | weight + r.strength) AS TotalStrength
计算路径上所有关系强度的总和。
这些基础查询模式涵盖了大多数常见的图数据查询需求。通过组合和扩展这些模式,可以构建更复杂、更强大的查询来解决各种业务问题。随着对Cypher的深入理解和实践,您将能够设计出更高效、更精确的查询来满足特定需求。
4.5 小结
本章介绍了Cypher的基本语法和查询操作,包括与SQL的对比、基本查询子句、数据创建和修改命令,以及常见的查询模式。通过掌握这些基础知识,您可以开始使用Cypher进行图数据的查询和操作。