【发布时间】:2016-12-21 01:30:57
【问题描述】:
我使用 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 for nodes with same property),
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
【问题讨论】: