多标签节点的最优Neo4j索引策略

问题描述 投票:0回答:2

我使用 Neo4j 来代表我们的数据仓库。我们有约 100,000 个各种类型的节点(约 10 个),其中一些具有多个标签。典型节点类型的子集是:

(:User)
(:Tableau:Workbook)
(:Tableau:Dashboard)

这里

Tableau
代表数据可视化软件,
Workbook
Dashboard
是不同的 Tableau 实体。我们使用多个标签而不是单个唯一定义的标签的原因是,人们可能希望匹配所有
(:Tableau)
节点或所有
(:Dashboard)
节点(我们有多个仪表板源)。

我还使用 GraphAware Neo4j UUID 库 (https://github.com/graphaware/neo4j-uuid) 来确保每个节点(无论类型)通过

uuid
节点属性进行唯一标识。

我为每个节点标签创建了一个索引(和唯一性约束)以提高性能,即

CREATE INDEX ON:User(uuid)
CREATE INDEX ON:Tableau(uuid)
CREATE INDEX ON:Workbook(uuid)
CREATE INDEX ON:Dashboard(uuid)

鉴于

CREATE INDEX
必须恰好采用一个标签。

在给定此索引结构的情况下使用 Cypher 匹配节点时,我遇到了一些性能问题。即使

(:Tableau:Dashboard)
<<
(:Tableau)
的基数,以下查询也不是最优的

MATCH (n:Tableau:Dashboard) WHERE n.uuid = <UUID> 

与任一者相比

MATCH (n:Tableau) WHERE n.uuid = <UUID> 
MATCH (n:Dashboard) WHERE n.uuid = <UUID> 

鉴于前者不利用任何指数,而后者却利用任何指数。如果想要仅根据 UUID(唯一)全局查找节点,这个问题就会变得更加复杂,当我们使用 Flask API 查找节点时经常出现这种情况,这会转化为以下 Cypher 逻辑:

MATCH(n) WHERE n.uuid = <UUID>

以下线程建议创建一个

Entity
总体全局节点标签并在其上创建索引(Neo4j:为具有相同属性的节点创建索引),

CREATE INDEX ON:Entity(uuid)

所以现在节点标记如下,

(:Entity:User)
(:Entity:Tableau:Workbook)
(:Entity:Tableau:Dashboard)

这是最好的方法吗?另一种解决方案是,如果定义了多个标签,并且保证被索引,则只选择第一个标签,但这并不能解决仅根据 UUID 查找节点的问题。

如果我采用

Entity
标签方法,保留所有先前定义的索引仍然有意义吗?也就是说,如果我只搜索一小部分节点,我是否会期望看到显着的性能改进?例如,如果我知道
n
是一个
(:User)
节点,我是否应该期望看到类似的性能,

MATCH (n:Entity) WHERE n.uuid = <UUID>
MATCH (n:User) WHERE n.uuid = <UUID>

无法对一个或多个索引建立索引是一种耻辱,因为最佳 Cypher 查询可能更加抽象,也就是说,假设

(:Tableau:Workbook)
填充
(:Tableau:Dashboard)
,然后查找工作簿填充的仪表板将查询,

MATCH (s:Tabeau:Workbook)-[:POPULATES]->(t:Tableau:Dashboard)
WHERE s.uuid = <UUID>
RETURN t

这是相当透明的,但是从性能角度来看,以下内容会更优化,尽管不太透明,因为用户不清楚

s
是什么类型的节点,

MATCH (s:Entity)-[:POPULATES]->(t:Tableau:Dashboard)
WHERE s.uuid = <UUID>
RETURN t
neo4j cypher
2个回答
4
投票

您正在维护

Tableau
Workbook
以及
Tableau
Dashboard
的重叠索引。为什么不只维护
Tableau
的索引来消除冗余,并用
USING INDEX
向查询规划器发出提示,以确保它在您的匹配中使用。即类似这样的东西...

MATCH (s:Tableau:Workbook)-[:POPULATES]->(t:Tableau:Dashboard)
USING INDEX s:Tableau(uuid)
WHERE s.uuid = <UUID>
RETURN t

0
投票

对于那些找到此线程的人,即使有 2 个以上标签,Neo4j 的最新版本(我使用的是 v5)也会使用索引。

示例

MATCH (s:Tableau:Workbook) WHERE s.uuid = <uuid>

假设您在

Tableau
上有索引,但在 Workbook 上没有
,这与 OP 中的情况略有不同。

    Neo4j 仍然首先达到
  1. Tableau
     索引
  2. 从那里,它会过滤结果
  3. :Workbook
这比

s:Tableau

慢了一根头发,但可能可以忽略不计。

文档

来自

搜索性能指数

“如果有多个索引可用,Cypher planner 将尝试使用能够最有效地解决特定谓词的索引(或多个索引)”

索引提示

文档阐明您仍然可以添加USING INDEX提示(根据

@dave-bennett
的好建议,但这仅在更高级的情况下才有必要。

© www.soinside.com 2019 - 2024. All rights reserved.