使用计数存储进行快速计数
Neo4j 维护一个事务性计数存储,用于保存许多事物的计数元数据。
计数存储用于告知查询计划器,以便它可以对如何计划查询做出明智的选择。
从计数存储获取计数是恒定时间,因此如果您想要从计数存储中获取某些内容的计数,则可以快速查询。
您可以通过查看查询的 EXPLAIN 生成的查询计划来判断您的查询是否正在使用计数存储。您应该看到 NodeCountFromCountStore
或 RelationshipCountFromCountStore
操作符。
计数存储查询的限制
根据定义,获取计数的查询必须具有 count()
聚合函数。
不能存在 WHERE 子句,也不能在匹配模式中存在任何内联属性。
由于查询计划器的限制,只有当 count()
聚合函数单独位于 WITH 或 RETURN 中时,才会利用计数存储。**如果除了 count()
聚合函数之外,还有任何其他变量在作用域内,则不会使用计数存储。**
如前所述,您可以通过在查询计划中检查 NodeCountFromCountStore
或 RelationshipCountFromCountStore
来判断是否正在使用计数存储。
本文末尾将讨论在同一查询中需要多个计数时的解决方法。
节点计数
您可以使用计数存储获取数据库中所有节点的计数
MATCH (n)
RETURN count(n) as count
您还可以获取给定标签的所有节点的计数
MATCH (n:Person)
RETURN count(n) as count
对于这些类型的查询,变量是可选的,因此您可以省略它们并使用 count(*)
代替,结果相同
MATCH ()
RETURN count(*) as count
以及
MATCH (:Person)
RETURN count(*) as count
限制 - 无法使用计数存储查询具有多个标签的节点
当查询具有多个标签的节点时,不会使用计数存储,因为计数存储中不会跟踪这些计数。
以下**不会**使用计数存储
MATCH (n:Person:Director)
RETURN count(n) as count
关系计数
计数存储还保存关系计数元数据,此处使用的模式必须描述单个关系模式。请注意,查询**必须**在匹配模式中使用有向关系才能使用计数存储,不要省略方向。
无论是否存在关系类型,都可以使用计数存储
MATCH ()-[r]->()
RETURN count(r) as count
MATCH ()-[r:ACTED_IN]->()
RETURN count(r) as count
当查询多种类型的关系时,计数存储也将被使用,这只会将每种类型的计数加在一起
MATCH ()-[r:ACTED_IN|DIRECTED]->()
RETURN count(r) as count
与节点一样,此处变量是可选的,可以使用 count(*)
代替
MATCH ()-[:ACTED_IN]->()
RETURN count(*) as count
到/来自具有单个标签的节点的关系计数
计数存储还保留关于单个端节点标签的关系计数。以下查询将从计数存储获取其计数。
MATCH ()-[r:ACTED_IN]->(:Movie)
RETURN count(r) as count
MATCH (:Person)-[r:ACTED_IN]->()
RETURN count(r) as count
MATCH ()-[r]->(:Movie)
RETURN count(r) as count
限制 - 无法在起始节点和结束节点上都存在标签的情况下使用计数存储
计数存储不会保留关于起始节点和结束节点上标签的元数据。
以下**不会**使用计数存储
MATCH (:Person)-[r:ACTED_IN]->(:Movie)
RETURN count(r) as count
在单个查询中获取多个计数
在您希望在单个查询中从计数存储获取多个计数的情况下,您可能会遇到本文开头提到的限制:count()
聚合函数必须单独位于 WITH 或 RETURN 行中才能使用计数存储。
此限制有两个值得注意的解决方法。
使用 UNION ALL 查询获取计数
如果我们使用计数存储为单独的查询获取计数并将它们 UNION 起来,我们可以通过一些额外的工作获得所需的计数
MATCH (n:Person)
WITH count(n) as count
RETURN 'Person' as label, count
UNION ALL
MATCH (n:Movie)
WITH count(n) as count
RETURN 'Movie' as label, count
请注意,我们需要另一个变量来提供上下文,但我们必须在获取 count()
之后才引入该变量,因为在聚合时引入的额外变量会阻止使用计数存储。
或者,我们可以返回一个映射结构,其中标签的类型及其关联的计数包含在映射中
MATCH (n:Person)
RETURN {label:'Person', count: count(n)} as info
UNION ALL
MATCH (n:Movie)
RETURN {label:'Movie', count: count(n)} as info
使用 apoc.cypher.run() 动态获取每个标签/类型的计数
apoc.cypher.run()
可用于每行执行单个 Cypher 查询,这可以允许您每行从计数存储获取计数。
结合获取节点标签或关系类型的调用,这可能是同时自动快速获取多个计数的有效方法
对于标签
CALL db.labels() YIELD label
CALL apoc.cypher.run('MATCH (:`'+label+'`) RETURN count(*) as count',{}) YIELD value
RETURN label, value.count
对于关系
CALL db.relationshipTypes() YIELD relationshipType as type
CALL apoc.cypher.run('MATCH ()-[:`'+type+'`]->() RETURN count(*) as count',{}) YIELD value
RETURN type, value.count
使用 APOC 过程中的 apoc.meta.stats()
您需要选择并选择要显示的 apoc.meta.stats()
调用中的哪些数据。
apoc.meta.stats()
调用会 YIELD 以下值
labelCount
- 图中标签的数量。
relTypeCount
- 图中关系类型的数量。
propertyKeyCount
- 图中属性键的数量。
nodeCount
- 图中节点的总数。
relCount
- 图中关系的总数。
labels
- 每个标签及其节点计数的映射。
relTypes
- 每个关系模式(仅限类型化关系,包括在一个端节点上带有标签的模式)及其关联计数的映射。
relTypesCount
- 每个关系类型及其计数的映射。
stats
- 包含上面提到的所有计数数据的映射。
labels
计数通常是最有用的,但类似的方法可用于其他计数
CALL apoc.meta.stats() YIELD labels
RETURN labels
这可能会返回一个类似于以下内容的映射:
{
"Movie": 38,
"Word": 12,
"News": 2,
"Director": 28,
"Reviewer": 3,
"Person": 133,
"Sentence": 17
}
获取其中一个值就像使用点符号获取键的值一样简单。
CALL apoc.meta.stats() YIELD labels
RETURN labels.Person as personCount
如果需要多个值,我们可以使用映射投影获取仅包含我们想要计数的映射
CALL apoc.meta.stats() YIELD labels
RETURN labels {.Person, .Movie, .Director} as counts
此页面是否有帮助?