使用计数存储进行快速计数
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 Procedures 中的 apoc.meta.stats()
APOC Procedures 包含 元数据过程,可用于一次性访问几乎所有计数存储数据。
您需要选择并显示 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
此页面有帮助吗?