Cypher笔记(二)

Cypher笔记(二)

1.模式

索引和约束时图的模式,Cypher引入了数据定义语言(Data Definition Language,DDL)来操作模式。

a.索引

索引是为了提高数据检索效率而引入的冗余信息,代价是需要维护额外的数据使得写入时更慢。Cypher允许所有节点的某个属性上有特定的标签。索引一旦创建,它将自己管理并当图发生变化时自动更新。多因创建并生效后,Neo4j将自动开始使用索引。

CREATE INDEX ON :Person(name) // 在拥有Person标签的所有节点的name属性上创建了索引
DROP INDEX ON :Person(name) // 删除拥有Person标签的所有节点的name属性上的索引
MATCH (person:Person { name: 'Andres' }) RETURN person
// 查询中不需要指出使用哪个索引,Cypher自己会决定,这里如果存在Person(name)索引,Cypher会自动使用

b.约束

Neo4j通过约束保证数据完整性。约束可用于节点或者关系,可以创建节点属性的唯一性约束,也可以创建节点和关系的属性存在约束。
可以使用属性的唯一性约束确保拥有特定标签的所有节点或者拥有特定类型的所有关系的属性是存在的,所有的试图创建新的没有该属性的节点或关系,以及试图删除强制属性的查询都将失败。
可以使用属性的存在性约束确保拥有特定标签的所有节点或者拥有特定类型的所有关系的属性是存在的,所有试图创建新的没有改属性的节点或关系,以及试图删除强制属性的查询都将失败。只有Neo4j企业版有属性存在性约束这个高级功能。

  • 可以对某个给定标签添加多个约束,唯一性约束和存在性约束可以同时添加到同一个属性上
  • 添加约束是一个需要花一段时间的原子操作,在所有已存在的数据被扫描完之前,这个约束不会生效
  • 若已存在某个节点或关系没有某个属性,再对这个属性创建存在性约束会失败
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE // 创建唯一性约束
DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE // 删除唯一性约束
CREATE CONSTRAINT ON (book:Book) ASSERT exists(book.isbn) // 创建节点属性存在性约束
DROP CONSTRAINT ON (book:Book) ASSERT exists(book.isbn) // 删除节点属性存在性约束
CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day) // 创建关系属性存在性约束

c.统计

当执行一个Cypher查询时,它将先编译为一个执行计划。为了给查询提供一个高效的计划,Neo4j需要数据库的信息

  • 拥有特定标签的节点的数量
  • 每个索引的可选择性
  • 按类型分的关系的数量
  • 以拥有指定标签的节点开始或者结束的关系,按类型分各自的数量

配置这些统计信息的更新
* dbms.index_sampling.background_enabled 控制当需要更新时索引是否自动重新采样
* dbms.index_sampling.update_percentage 控制多大比例的索引被更新后才触发新的采样
* cypher.statistics_divergence_threshhold 控制一个执行计划被认为过时要重新生成前,允许多少统计信息发生变化。任何统计信息的相对变化超过临界值,原有执行计划将被丢弃并创建一个新的计划,0.0=有变化就更新,1.0=永远不更新

Cypher根据可用索引构建执行计划,这些索引决策一直有效直到数据模式发生变化。所以增加和删除索引都会导致缓存的执行计划被刷新

手动索引采样
* cypher-shell ‘CALL db.resampleIndex(“:Person(name)”);’
* cypher-shell ‘CALL db.resampleOutdatedIndexes();’

2.查询调优

查询性能优化的总目标是确保只从图中检索必要的数据,不必要的数据应该尽可能早地被过滤掉,以减少后期处理的数据量。

查询计划器

查询计划器有用于产生查询计划的规则。它会考虑所有可用的索引,但不使用统计信息去指导查询编译。计划器使用统计服务为所有可选的查询赋予一个成本,然后选择耗费最少的那个。默认情况下,Neo4j 3.1对所有查询使用成本计划器。可以通过使用 cypher.planner 配置来强制使用制定的计划器。

  • 查看查询计划:在查询语句中加入EXPLAIN
  • 查看哪个运算符占了大部分工作:在查询语句中加入PROFILE。此时会跟踪传递了多少行数据给每个运算符,以及每个运算符和存储曾交互了多少以获取必要的数据。注意PROFILE会占用更多的资源,建议只用于做性能分析

USING

USING语句用于为一个查询构建执行计划时影响计划器的决定。通过USING来强制Neo4j使用一个特定的开始点,这个被称为计划器提示
* 索引提示用于告知计划器无论在什么情况下都应使用指定的索引作为开始点。使用在MATCH后添加USING INDEX variable:Label(property)来补充索引提示。可以使用多个索引提示,但多个开始点会在后面的查询计划中潜在地需要额外的连接
* 扫描提示:在MATCH后面使用USING SCAN variable:Label,将强制Cypher不使用本应使用的索引,而采用标签扫描
* 连接提示:强制在特定的点进行连接。使用USING JOIN ON variable

3.执行计划

Neo4j把执行一个查询的任务分解为一些称为运算符的小块,这些以模式形式连接在一起的运算符称为一个执行计划。每个运算符用如下统计信息来注解:

  • Rows:Row运算符产生的行数,只有带有profile的查询才有
  • EstimatedRows:使用基于成本的编译器,可以看到由运算符产生的预估的行数。编译器使用这个估值来选择合适的执行计划
  • DbHits:每个运算符都会向Neo4j存储引擎请求像检索或者更新数据这样的工作,一次数据库命中是存储引擎工作的一个抽象单位

开始点运算符

这些运算符用于找到图的开始点

  • 全节点扫描(AllNodesScan):从节点库读取所有节点
  • 通过id搜索有向关系(DirectedRelationshipByIdSeekPipe):从关系库通过id来读取一个或多个关系将返回关系和两端的节点
  • 通过id寻找节点(NodeByIdSeek)
  • 通过标签扫描检索节点(NodeByLabelScan)
  • 通过索引检索节点(NodeIndexSeek)
  • 通过索引范围寻找节点(NodeIndexSeekByRange):使用索引检索节点,节点的属性值满足给定的字符串前缀,用于STARTS WITH和比较符号
  • 通过索引包含扫描检索节点(NodeIndexContainsScan):一个节点的包含扫描将遍历存储在索引中的所有值,搜索实体中是否包含指定的字符串
  • 通过索引扫描检索节点(NodeIndexScan):遍历存储在索引中的所有值,找到拥有特定标签和属性的所有节点(如 exists(n.prop))
  • 通过id寻找无方向关系(UndirectedRelationshipByIdSeek)

Expand元算符

  • Expand All(Expand(All)):给定一个开始节点,expand-all将根据关系中的模式沿开始节点或者结束节点展开,能处理变长模式的关系
  • Expand Into(Expand(Into)):当开始节点和结束节点都已经找到时,expand-into用于找到两个节点之间连接的所有关系
  • 可选Expand All(OptionalExpand(All)):从一个给定节点开始遍历关系,确保在返回结果之前断言得到处理,针对OPTOINAL MATCH

组合运算符

256 用于将其他运算符拼接在一起

  • Apply:Apply以嵌套循环的方式工作。Apply运算符左端返回的每一行作为右端运算符的输入,然后Apply将产生组合的结果
  • SemiApply:测试一个模式断言的存在性。SemiApply从它的子运算符中获取一行,并将其作为右端的叶节点运算符的输入。如果右端运算符至少产生一行结果,左端的这一行由SemiApply运算符产生。这使得SemiApply成为一个过滤运算符,可以大量运用在查询的模式断言中
  • AntiSemiApply:测试一个模式断言的存在性。和SemiApply相反,它进行反向过滤
  • LetSemiApply:测试模式断言的存在性。当一个查询包含多个模式断言时,LetSemiApply将用于处理它们中的地一个。它会记录断言的评估结果,但会留下过滤器到另外一个运算符
  • LetAntiSemiApply:当一个查询包含多个模式断言时,LetAntiSemiApply将用于处理它们中的第一个。它会记录断言的评估结果,但会留下过滤器到另外一个运算符
  • SelectOrSemiApply:测试一个模式断言的存在性并评估一个断言。这个运算符允许将一般的断言与检查存在性的断言放在一起。首先评估普通表达式,仅当它返回false时模式断言才会执行
  • SelectOrAntiSemiApply:测试一个模式断言的存在性并评估一个断言
  • ConditionalApply:检查一个变量是否不为null,如果是那么执行右边的部分
  • AntiConditionalApply:检查一个变量是否为null,如果是那么执行右边的部分
  • AssertSameNode:用于确保没有违背唯一性约束
  • NodeHashJoin:使用哈系表,NodeHashJoin将来自左端和右端的输入连接起来
  • 三元(Triadic):用于解决三元查询,如查找我朋友的朋友中那些还不是我朋友的人。它把所有的朋友放入一个集合,然后再检查他们是否已经与我相连

行运算符

将其他运算符产生的行转换为一个新的行集合

  • Eager:确保在继续之前将那些会影响后续操作的运算在整个数据集上被完全地执行
  • Distinct:移除输入流中重复的行
  • Eager聚合:即时加载潜在的结果并存入哈系map中,使用分组键作为map的键
  • 从计数库获取节点数量:比通过计数方式的Eager聚合更快,但计数库只保存了有限范围的组合,因此Eager聚合对很多复杂的查询依然很有用
  • 从计数库获取关系数量:同上
  • 过滤:过滤来自在子运算符的每一行,仅仅让断言成为true的结果通过
  • Limit:返回输入的前n行
  • Projection:对于输入的每一行,projection将评估表达式并产生一行表达式的结果
  • Skip:跳过输入行的前n行
  • Sort:根据给定的键进行排序
  • Top:返回根据给定键排序后的前n行
  • Union:将左右两个计划的结果连接在一起
  • Unwind:将列表中的值以每行一个元素的形式返回
  • 调用过程:返回以name为序的所有标签

更新运算符

  • 约束操作(CreateUniqueConstrain):在一对标签和属性上创建一个约束
  • EmptyResult(EmptyResult):即时加载产生所有结果到EmptyResult运算符并丢弃掉
  • 更新图(UpdateGraph):对图进行更新操作
  • Merge Into(Merge(Into)):当开始和结果节点都已经找到,Merge Into用于找到这两个节点之间的所有关系或者创建一个新的关系

最短路径规划

用快速算法检索最短路径
MATCH (ms:Person { name: 'Martin Sheen' }), (cs: Person { name: 'Charlie Sheen' }), p = shortestPath((ms)-[rels:ACTED_IN*]-(cs))
WHERE ALL (r IN rels WHERE exists(r.role)) RETURN p

这个查询可以使用快速算法——因为没有断言需要查看所有路径

需要检查路径上额外断言的最短路径规划
  • 考虑使用穷举搜索:在决定哪条是最短的匹配路径之前,WHERE语句中的断言需要应用于最短路径模式
MATCH (cs:Person { name: 'Charlie Sheen' }), (ms:Person { name: 'Martin Sheen'}), p = shortestPath((cs)-[*]-(ms))
WHERE length(p) > 1 RETURN p // 与上个例子不同,这个查询在知道哪条是最短路径之前,需要检查所有的路径
  • 禁止使用穷举搜索算法:使用with语句将使得查询计划不使用穷举搜索算法。有快速算法找到的任何路径接下来将被过滤掉,这可能会导致没有结果返回
MATCH (cs:Person { name: 'Charlie Sheen' }), (ms:Person { name: 'Martin Sheen' }), p  = shortestPath((cs)-[*]-(ms))
WITH p WHERE length(p) > 1 RETURN p
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值