Python 参数为列表的neo4j cypher性能
我们正在运行neo4j版本3.3。 我们有两种类型的节点(总共10k个节点),它们总共有650k个关系。我们的内存堆大小为8GB。Python 参数为列表的neo4j cypher性能,python,neo4j,cypher,Python,Neo4j,Cypher,我们正在运行neo4j版本3.3。 我们有两种类型的节点(总共10k个节点),它们总共有650k个关系。我们的内存堆大小为8GB。 节点在节点ID上具有唯一约束 我们正在使用官方的neo4jpython官方驱动程序(我们也尝试使用py2neo驱动程序,但性能更差)。 运行以下查询时,性能非常有问题。对于1跳距离,它需要几分钟(即使对于多个节点的列表也是如此)。对于一个包含1个节点的列表的2跳距离(如下面的查询),它需要超过40分钟。 有什么办法可以提高性能吗 query = '''MATCH (
节点在节点
ID
上具有唯一约束
我们正在使用官方的neo4jpython
官方驱动程序(我们也尝试使用py2neo
驱动程序,但性能更差)。
运行以下查询时,性能非常有问题。对于1跳距离,它需要几分钟(即使对于多个节点的列表也是如此)。对于一个包含1个节点的列表的2跳距离(如下面的查询),它需要超过40分钟。
有什么办法可以提高性能吗
query = '''MATCH (n1:label1)
WHERE n1.ID IN {list}
MATCH paths=((n1)-[:relType*..2]->(n2))
WHERE n1.ID <> n2.ID AND (n2:label1 OR n2:label2)
RETURN DISTINCT paths
UNION
MATCH (n1:label2)
WHERE n1.ID IN {list}
MATCH paths=((n1)-[:relType*..2]->(n2))
WHERE n1.ID <> n2.ID AND (n2:label1 OR n2:label2)
RETURN DISTINCT paths'''
with driver.session() as session:
results = list(session.run(query, parameters={'list':list_nodes}))
if results:
df = neo4j_graph_to_df(results)
您可以尝试在n.ID
属性中创建索引:
CREATE INDEX ON :label1(ID)
CREATE INDEX ON :label2(ID)
请注意,索引是由数据库在后台任务中创建的。一旦索引创建并上线,Neo4j将自动拾取并开始使用该索引
此外,请尝试将查询更改为仅使用一个匹配项,而不是两个:
MATCH paths=((n1:label1)-[:relType*..2]->(n2))
WHERE n1.ID IN {list} AND n1.ID <> n2.ID AND (n2:label1 OR n2:label2)
RETURN DISTINCT paths
UNION
MATCH paths=((n1:label2)-[:relType*..2]->(n2))
WHERE n1.ID IN {list} AND n1.ID <> n2.ID AND (n2:label1 OR n2:label2)
RETURN DISTINCT paths
匹配路径=((n1:label1)-[:relType*.2]->(n2))
其中{list}中的n1.ID和n1.ID n2.ID和(n2:label1或n2:label2)
返回不同的路径
联合
匹配路径=((n1:label2)-[:relType*.2]->(n2))
其中{list}中的n1.ID和n1.ID n2.ID和(n2:label1或n2:label2)
返回不同的路径
您声明在节点ID
”上有“一个唯一约束
”,但实际上需要两个约束(或索引)。每个节点标签(label1
和label2
)都需要在ID
属性上有自己的约束(或索引)。例如:
CREATE CONSTRAINT ON (lab1:label1) ASSERT lab1.ID IS UNIQUE;
CREATE CONSTRAINT ON (lab2:label2) ASSERT lab2.ID IS UNIQUE;
MATCH (n1:label1)
WHERE n1.ID IN {list}
WITH COLLECT(n1) AS ns1
MATCH (n2:label2)
WHERE n2.ID IN {list}
WITH ns1 + COLLECT(n2) AS startNodes
CALL apoc.path.expandConfig(
startNodes,
{labelFilter: '>label1|>label2', minLevel: 1, maxLevel: 2}
) YIELD path
RETURN DISTINCT path;
使用上述约束(或索引),此查询应该更快:
MATCH (n1:label1)
USING INDEX n1:label1(ID)
WHERE n1.ID IN {list}
WITH COLLECT(n1) AS ns1
MATCH (n2:label2)
USING INDEX n2:label2(ID)
WHERE n2.ID IN {list}
WITH ns1 + COLLECT(n2) AS ns
UNWIND ns AS n
OPTIONAL MATCH path1=(n)-[:relType*..2]->(n31:label1)
WHERE n.ID <> n31.ID
OPTIONAL MATCH path2=(n)-[:relType*..2]->(n32:label2)
WHERE n.ID <> n32.ID
WITH COLLECT(path1) + COLLECT(path2) AS paths
UNWIND paths AS path
RETURN DISTINCT path
谢谢你的建议。因为我有一个约束,所以不需要索引。更改为一场比赛并没有提高性能…你好@JosephBerry!既然联合
中两个查询之间的唯一区别是关系方向,为什么不删除匹配
中的方向并避免联合
?这样:匹配路径=((n1)-[:relType*.2]->(n2)),其中{list}中的n1.ID和n1.ID n2.ID以及(n1:label1或n1:label2)和(n2:label1或n2:label2)返回不同的路径
。试试看,如果有帮助请告诉我!:)
MATCH (n1:label1)
WHERE n1.ID IN {list}
WITH COLLECT(n1) AS ns1
MATCH (n2:label2)
WHERE n2.ID IN {list}
WITH ns1 + COLLECT(n2) AS startNodes
CALL apoc.path.expandConfig(
startNodes,
{labelFilter: '>label1|>label2', minLevel: 1, maxLevel: 2}
) YIELD path
RETURN DISTINCT path;