Python 参数为列表的neo4j cypher性能

Python 参数为列表的neo4j cypher性能,python,neo4j,cypher,Python,Neo4j,Cypher,我们正在运行neo4j版本3.3。 我们有两种类型的节点(总共10k个节点),它们总共有650k个关系。我们的内存堆大小为8GB。 节点在节点ID上具有唯一约束 我们正在使用官方的neo4jpython官方驱动程序(我们也尝试使用py2neo驱动程序,但性能更差)。 运行以下查询时,性能非常有问题。对于1跳距离,它需要几分钟(即使对于多个节点的列表也是如此)。对于一个包含1个节点的列表的2跳距离(如下面的查询),它需要超过40分钟。 有什么办法可以提高性能吗 query = '''MATCH (

我们正在运行neo4j版本3.3。 我们有两种类型的节点(总共10k个节点),它们总共有650k个关系。我们的内存堆大小为8GB。
节点在节点
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;