Neo4j Cypher Optimize在笛卡尔积中的每个节点之间建立关系

时间:2016-11-14 12:05:44

标签: neo4j cypher

我有一组节点,都标记为Word。我想用一个名为Distance的关系将每个单词连接到所有其他单词。我做了以下查询:

match (word1:Word)
with word1
match (word2:Word)
where word1 <> word2
merge (word1)-[distance:DISTANCE ]->(word2)
return word1, distance, word2

它永远运行。只有约600个节点,虽然我期望600 * 600的关系,但查询不应该运行两个小时!它在Java中比在Neo4j中更快。你有什么建议让它更快?我已经在其中一个属性上添加了一个索引,但它没有改进。

1 个答案:

答案 0 :(得分:3)

一些观察结果:

  1. 您的查询将尝试在单个交易中执行2 * 600 * 599(或718,800)MERGE次操作。因子2的原因是因为每对单词(例如,x和y)将被看到两次(如x / y和y / x)。你(大概)只想执行一半的操作。
  2. x / y和y / x行为还会导致尝试确保每个单词对有两个DISTANCE关系 - 一个方向都是一个。这(大概)是你想要(或需要)的关系数量的两倍。
  3. 尝试在单个事务中执行720K(甚至只是360K)操作可能会导致数据库服务器内存不足。
  4. 这是一个修改过的查询,可能会解决上述问题。 ID(w1) < ID(w2)测试确保一对中的2个单词不相同并且同一对只处理一次。它还使用APOC过程apoc.periodic.iterate在单独的事务中一次创建10K关系。

    CALL apoc.periodic.iterate(
      'MATCH (w1:Word), (w2:Word) WHERE ID(w1) < ID(w2) RETURN w1, w2',
      'CREATE (w1)-[:DISTANCE]->(w2)',
      {batchSize:10000, parallel:true}) YIELD batches, total
    RETURN *
    

    注意1:此查询假定您在数据库中没有任何DISTANCE关系的情况下开始,因此它使用更便宜的CREATE子句而不是MERGE。如果已存在DISTANCE关系,则使用MERGE代替(但如果第一个关系方向相反,这可能会在同一对之间创建第二个关系)。

    注意2:并行执行批处理应该是安全的,因为新的Cypher代码无法解决问题#2。如果2个事务试图同时在相同的2个节点之间以相反的方向创建关系,则可能导致deadlock,这将导致至少一个事务失败。 < / p>

    注3:此查询假定第一个语句(带有MATCH子句)本身不会耗尽内存或处理时间过长。如果该假设是错误的,那么使用apoc.periodic.commit的适当修改的查询应该有效。