【问题标题】:Neo4j: Fast query for getting relationships between a set of nodesNeo4j:获取一组节点之间关系的快速查询
【发布时间】:2015-04-08 03:28:19
【问题描述】:

我正在寻找一个快速的 Cypher 语句,它返回一组已知节点(我有他们的 Neo4j ID)之间的所有关系,以便我可以为该特定节点集组装子图。我在一个名为 label 的标签中工作,它有大约 50K 节点和这些节点之间的 800K 边。

对此我有几种工作方法,但对于我的应用程序来说,没有一种方法足够快,即使是在较小的集合大小(少于 1000 个节点)时也是如此。

例如,以下语句可以解决问题:

MATCH (u:label)-[r]->(v:label)
WHERE (ID(u) IN {ids}) AND (ID(v) IN {ids}) 
RETURN collect(r)

{ids} 是作为 Py2Neo cypher.execute(statement, parameters) 方法的参数提供的数字 Neo4j id 的列表。问题是一组 838 个节点需要大约 34 秒,它返回它们之间的所有 19K 关系。我意识到该图有点密集,但每返回 1000 条边需要 1.76 秒。我只是不认为这是可以接受的。

如果我改用 START 子句(如下所示),时间实际上会差一些。

START u=node({ids}), v=node({ids})
MATCH (u:label)-[r]->(v:label)
RETURN collect(r) 

我发现了许多类似的问题/答案,但它们在某些方面都不尽如人意。有没有更好的说明,甚至更好的图形模式,以便它可以扩展到数千个节点的集合?


更新

感谢您的快速回复。首先,要运行我当前对 528 个节点的查询作为输入 (len(ids)=528),它需要 32.1 秒,查询计划如下。

NodeByIdSeek: 528 hits
Filter      : 528 hits
Expand(All) : 73,773 hits
Filter      : 73,245 hits
Projection  : 0 hits
Filter      : 0 hits

Brian Underwood 的查询使用相同的输入,需要 27.8 秒。查询计划是相同的,除了最后两个步骤(投影和过滤器),他的查询不存在这些步骤。但是 db hits sum 是一样的。

Michael Hunger 的查询耗时 26.9 秒,查询计划与 Brian 的查询相同。

我在实验之间重新启动了服务器以避免缓存影响(可能有更聪明的方法来做到这一点)。我还直接从 Web 界面查询,以绕过我的代码和我正在使用的库中可能存在的瓶颈。

底线,Neo4j 似乎足够聪明,可以优化我的查询,但是即使是相当小的集合,它仍然很慢。有什么建议吗?

【问题讨论】:

  • 将第一行改成MATCH (u:label)-[r]-(v:label)会有性能变化吗?
  • 你能分享你的查询计划吗?您可以通过在查询前加上 PROFILE 来获取它
  • 不返回 collect(r) 只是 r
  • 你的用例是什么? (你当然不能显示这个图表)也许你应该改变你的策略,只得到你处理的图表部分?如果你让我知道你的目标是什么,帮助会更容易
  • @jag426 对于 528 个节点的相同输入,它花费了 7 倍的时间。我还必须处理重复项。

标签: performance neo4j cypher


【解决方案1】:

我认为问题在于查询正在做笛卡尔积以获取 838 节点的所有组合,因此您最终会搜索 838*838=702,244 个组合。

我很好奇它会如何执行:

MATCH (u:label)-[r]->(v:label)
WHERE (ID(u) IN {ids})
WITH r, v
WHERE (ID(v) IN {ids})
RETURN collect(r)

另外,为什么collect在最后?

【讨论】:

  • collect 使使用 python 库中的结果变得更容易,但我已经放弃了它。似乎 Neo4j 将我的查询优化为与您的类似。请检查我的更新。
  • 疯狂的想法:如果您返回所有节点并collected 所有这些节点的关系并返回所有结果会怎样。然后尝试过滤掉不需要的关系。
  • 但这就像为它做 Neo4j 工作,对吧?我转向图形数据库正是为了避免这类事情。
  • 是的,很公平。我更好奇它是如何工作的。这可能是 Neo4j 应该在内部实现的优化。
【解决方案2】:

您的 id 列表有多大?

试试这个:

MATCH (u) WHERE ID(u) IN {ids}
WITH u
MATCH (v)-[r]->(v)
WHERE ID(v) IN {ids}
RETURN count(*)


MATCH (u) WHERE (ID(u) IN {ids})
WITH u
MATCH (v)-[r]->(v)
WHERE ID(v) IN {ids}
RETURN r

还可以尝试通过在查询前加上 PROFILE 来创建查询计划,然后您会看到成本在哪里。

【讨论】:

  • 我假设您的意思是MATCH (u)-[r]->(v)。然而,性能并没有明显好转。请检查我的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多