外观
Neo4j Cypher查询语言基础
Cypher简介
什么是Cypher
- 定义:Cypher是Neo4j的声明式图查询语言,专为图数据设计
- 设计理念:类似SQL,但针对图数据进行了优化
- 可读性:语法简洁直观,使用ASCII艺术表示图结构
- 功能强大:支持创建、查询、更新和删除图数据
Cypher的特点
- 声明式语法:描述要做什么,而不是怎么做
- 图模式匹配:使用模式匹配查询图数据
- 关系优先:原生支持关系查询,无需JOIN操作
- 灵活的数据模型:支持动态schema
- 丰富的函数库:内置多种函数,支持复杂查询
Cypher与SQL的对比
| 特性 | Cypher | SQL |
|---|---|---|
| 数据模型 | 图结构 | 表格结构 |
| 查询方式 | 模式匹配 | JOIN操作 |
| 关系处理 | 原生支持 | 通过外键关联 |
| 灵活性 | 动态schema | 固定schema |
| 语法风格 | 直观的图模式 | 表格操作 |
| 适用场景 | 关系密集型查询 | 结构化数据查询 |
Cypher基础语法
核心概念
- 节点(Node):用
(n)表示,n是节点变量 - 关系(Relationship):用
-[r]->表示,r是关系变量,箭头表示方向 - 属性(Property):用
{key: value}表示,键值对结构 - 标签(Label):用
:Label表示,节点的分类 - 关系类型(Relationship Type):用
:TYPE表示,关系的分类
基本语法结构
节点表示
cypher
-- 空节点
()
-- 带有变量的节点
(n)
-- 带有标签的节点
(:User)
-- 带有变量和标签的节点
(u:User)
-- 带有多个标签的节点
(u:User:Customer)
-- 带有属性的节点
(u:User {name: '张三', age: 30})关系表示
cypher
-- 无方向关系
()-[]-()
-- 有方向关系
()-[]->()
-- 带有变量和类型的关系
()-[:FOLLOWS]->()
-- 带有属性的关系
()-[:FOLLOWS {since: 2023}]->()
-- 完整的关系表示
(u:User)-[r:FOLLOWS {since: 2023}]->(v:User)基本查询子句
MATCH子句
- 作用:指定要匹配的图模式
- 语法:
MATCH pattern - 示例:cypher
MATCH (u:User {name: '张三'})-[:FOLLOWS]->(v:User)
RETURN子句
- 作用:指定要返回的结果
- 语法:
RETURN expressions - 示例:cypher
MATCH (u:User {name: '张三'})-[:FOLLOWS]->(v:User) RETURN v.name, v.age
WHERE子句
- 作用:过滤匹配的结果
- 语法:
WHERE conditions - 示例:cypher
MATCH (u:User)-[:FOLLOWS]->(v:User) WHERE u.age > 25 AND v.age < 35 RETURN v.name
CREATE子句
- 作用:创建节点和关系
- 语法:
CREATE pattern - 示例:cypher
CREATE (u:User {name: '张三', age: 30}) CREATE (u:User)-[:FOLLOWS]->(v:User {name: '李四'})
MERGE子句
- 作用:创建或匹配节点和关系
- 语法:
MERGE pattern - 示例:cypher
MERGE (u:User {name: '张三'}) ON CREATE SET u.createdAt = datetime()
SET子句
- 作用:设置节点和关系的属性
- 语法:
SET properties - 示例:cypher
MATCH (u:User {name: '张三'}) SET u.age = 31, u.updatedAt = datetime()
REMOVE子句
- 作用:删除节点和关系的属性或标签
- 语法:
REMOVE properties | labels - 示例:cypher
MATCH (u:User {name: '张三'}) REMOVE u.age, u:VIP
DELETE子句
- 作用:删除节点和关系
- 语法:
DELETE elements - 示例:cypher
MATCH (u:User {name: '张三'}) DELETE u
DETACH DELETE子句
- 作用:删除节点及其所有关系
- 语法:
DETACH DELETE node - 示例:cypher
MATCH (u:User {name: '张三'}) DETACH DELETE u
Cypher查询操作
节点查询
查询所有节点
cypher
MATCH (n) RETURN n查询特定标签的节点
cypher
MATCH (u:User) RETURN u根据属性查询节点
cypher
MATCH (u:User {name: '张三'}) RETURN u使用WHERE子句过滤
cypher
MATCH (u:User) WHERE u.age > 25 AND u.active = true RETURN u.name, u.age限制返回结果
cypher
MATCH (u:User) RETURN u.name, u.age ORDER BY u.age DESC LIMIT 10关系查询
查询特定类型的关系
cypher
MATCH (u:User)-[:FOLLOWS]->(v:User) RETURN u.name, v.name查询反向关系
cypher
MATCH (u:User)<-[:FOLLOWS]-(v:User) RETURN u.name, v.name查询所有关系
cypher
MATCH (u:User)-[r]-(v:User) RETURN u.name, type(r), v.name查询多跳关系
cypher
-- 查询2度关系
MATCH (u:User)-[:FOLLOWS*2]->(v:User) RETURN u.name, v.name
-- 查询1到3度关系
MATCH (u:User)-[:FOLLOWS*1..3]->(v:User) RETURN u.name, v.name属性查询
查询特定属性
cypher
MATCH (u:User {name: '张三'}) RETURN u.name, u.age查询所有属性
cypher
MATCH (u:User {name: '张三'}) RETURN properties(u)使用属性函数
cypher
MATCH (u:User) RETURN u.name, toUpper(u.email), u.age + 5查询数组属性
cypher
MATCH (p:Product) WHERE '电子产品' IN p.tags RETURN p.nameCypher创建操作
创建节点
创建单个节点
cypher
CREATE (u:User {name: '张三', age: 30, email: 'zhangsan@example.com'})创建多个节点
cypher
CREATE
(u1:User {name: '张三', age: 30}),
(u2:User {name: '李四', age: 25}),
(u3:User {name: '王五', age: 35})创建带有多个标签的节点
cypher
CREATE (p:Person:Employee:Manager {name: '李四', department: 'IT'})创建关系
创建两个现有节点之间的关系
cypher
MATCH (u1:User {name: '张三'}), (u2:User {name: '李四'})
CREATE (u1)-[:FOLLOWS {since: date('2023-01-01')}]->(u2)创建节点和关系
cypher
CREATE (u1:User {name: '张三'})-[:FOLLOWS]->(u2:User {name: '李四'})创建多关系
cypher
CREATE
(u1:User {name: '张三'})-[:FOLLOWS]->(u2:User {name: '李四'}),
(u1)-[:FOLLOWS]->(u3:User {name: '王五'}),
(u2)-[:FOLLOWS]->(u3)Cypher更新操作
更新节点属性
cypher
MATCH (u:User {name: '张三'})
SET u.age = 31, u.updatedAt = datetime()
RETURN u更新关系属性
cypher
MATCH (u1:User {name: '张三'})-[r:FOLLOWS]->(u2:User {name: '李四'})
SET r.strength = 0.8, r.updatedAt = datetime()
RETURN r添加和删除标签
cypher
-- 添加标签
MATCH (u:User {name: '张三'}) SET u:VIP RETURN u
-- 删除标签
MATCH (u:User:VIP {name: '张三'}) REMOVE u:VIP RETURN u增加属性值
cypher
MATCH (p:Product {name: '手机'})
SET p.price = p.price + 100
RETURN pCypher删除操作
删除节点
cypher
-- 删除没有关系的节点
MATCH (u:User {name: '张三'}) DELETE u
-- 删除节点及其所有关系
MATCH (u:User {name: '张三'}) DETACH DELETE u删除关系
cypher
MATCH (u1:User {name: '张三'})-[r:FOLLOWS]->(u2:User {name: '李四'})
DELETE r删除属性
cypher
MATCH (u:User {name: '张三'}) REMOVE u.phone RETURN uCypher高级查询
聚合查询
cypher
-- 计算用户数量
MATCH (u:User) RETURN count(u) AS userCount
-- 计算平均年龄
MATCH (u:User) RETURN avg(u.age) AS averageAge
-- 按标签分组计算
MATCH (u:User) RETURN u.active, count(u) AS count GROUP BY u.active
-- 过滤分组结果
MATCH (u:User) RETURN u.department, avg(u.age) AS averageAge
GROUP BY u.department HAVING avg(u.age) > 30路径查询
cypher
-- 最短路径
MATCH shortestPath((u1:User {name: '张三'})-[r:FOLLOWS*]->(u2:User {name: '王五'}))
RETURN u1, r, u2
-- 所有最短路径
MATCH allShortestPaths((u1:User {name: '张三'})-[r:FOLLOWS*]->(u2:User {name: '王五'}))
RETURN u1, r, u2
-- 指定最大深度的路径
MATCH (u1:User {name: '张三'})-[r:FOLLOWS*1..3]->(u2:User {name: '王五'})
RETURN u1, r, u2图算法查询
cypher
-- 计算PageRank
CALL gds.pageRank.write('myGraph', {
writeProperty: 'pagerank'
})
-- 查找社区
CALL gds.louvain.write('myGraph', {
writeProperty: 'community'
})Cypher最佳实践
查询优化
- 使用标签过滤:优先使用标签过滤减少数据量
- 创建合适的索引:为频繁查询的属性创建索引
- 限制查询深度:避免过深的关系遍历
- 使用参数化查询:避免SQL注入,提高性能
- 避免笛卡尔积:确保模式匹配有明确的连接条件
数据建模
- 合理设计标签:使用清晰的标签分类节点
- 使用具体的关系类型:避免使用通用关系类型
- 关系方向有意义:关系方向应具有明确的语义
- 属性最小化:只存储必要的属性
- 避免超节点:拆分拥有大量关系的节点
性能监控
- 使用EXPLAIN和PROFILE:分析查询执行计划
- 监控查询性能:使用Neo4j监控工具跟踪查询性能
- 优化慢查询:识别并优化慢查询
- 定期清理数据:删除不再需要的数据
Cypher常见错误
语法错误
- 错误示例:缺少括号cypher
MATCH u:User RETURN u -- 错误,缺少括号 - 正确写法:cypher
MATCH (u:User) RETURN u
模式匹配错误
- 错误示例:不完整的模式cypher
MATCH (u:User)-[:FOLLOWS] RETURN u -- 错误,关系不完整 - 正确写法:cypher
MATCH (u:User)-[:FOLLOWS]->() RETURN u
属性类型错误
- 错误示例:类型不匹配cypher
MATCH (u:User) WHERE u.age = '30' RETURN u -- 错误,age是整数 - 正确写法:cypher
MATCH (u:User) WHERE u.age = 30 RETURN u
关系方向错误
- 错误示例:方向错误导致查询无结果cypher
MATCH (u1:User {name: '李四'})-[:FOLLOWS]->(u2:User {name: '张三'}) RETURN u1, u2 - 正确写法:cypher
MATCH (u1:User {name: '张三'})-[:FOLLOWS]->(u2:User {name: '李四'}) RETURN u1, u2
版本差异
Neo4j 3.x Cypher特性
- 支持基本的CRUD操作
- 支持图模式匹配
- 支持基本的聚合函数
- 支持路径查询
Neo4j 4.x Cypher特性
- 支持多数据库
- 增强的图算法支持
- 改进的查询计划器
- 支持更多数据类型
- 增强的函数库
Neo4j 5.x Cypher特性
- 并行查询执行
- 改进的查询性能
- 增强的图算法
- 支持更多空间数据类型
- 改进的错误消息
常见问题(FAQ)
Q1: Cypher区分大小写吗?
A1: Cypher的标签、关系类型和属性键是区分大小写的,而关键字、函数名和变量名不区分大小写。
Q2: 如何在Cypher中使用参数?
A2: 可以使用参数化查询,例如:
cypher
MATCH (u:User {name: $name}) RETURN u参数值在执行查询时传入,避免SQL注入,提高性能。
Q3: 如何处理Cypher查询中的特殊字符?
A3: 可以使用反斜杠转义特殊字符,或者使用参数化查询。例如:
cypher
MATCH (u:User {email: 'user\@example.com'}) RETURN uQ4: 如何限制Cypher查询的执行时间?
A4: 可以在Neo4j配置中设置查询超时时间,或者使用dbms.transaction.timeout参数限制事务时间。
Q5: 如何优化慢Cypher查询?
A5: 优化慢查询的方法包括:
- 分析查询执行计划
- 创建合适的索引
- 优化数据模型
- 限制查询深度
- 使用标签过滤
- 避免笛卡尔积
Q6: 如何使用Cypher导入数据?
A6: 可以使用LOAD CSV命令导入CSV数据,或者使用neo4j-admin import工具进行大规模数据导入。
Q7: 如何在Cypher中使用正则表达式?
A7: 可以使用=~操作符进行正则表达式匹配,例如:
cypher
MATCH (u:User) WHERE u.email =~ '.*@example\.com' RETURN uQ8: 如何计算两个节点之间的最短路径?
A8: 可以使用shortestPath函数计算最短路径,例如:
cypher
MATCH p = shortestPath((u1:User {name: '张三'})-[r*]->(u2:User {name: '李四'}))
RETURN pQ9: 如何在Cypher中使用聚合函数?
A9: 可以使用count、sum、avg、min、max等聚合函数,例如:
cypher
MATCH (u:User) RETURN count(u) AS userCount, avg(u.age) AS averageAgeQ10: 如何学习Cypher?
A10: 学习Cypher的资源包括:
- Neo4j官方文档
- Neo4j Cypherrefcard
- Neo4j Sandbox在线练习
- 图数据库相关书籍
- 社区教程和博客
