【问题标题】:Traversing through all nodes and comparing each one with every other one遍历所有节点并将每个节点与其他节点进行比较
【发布时间】:2015-07-05 13:20:21
【问题描述】:

我正在做一个小项目,我有一个包含大约 6 万个节点和这些节点之间的 50 万个关系的数据集。节点有两种类型。第一种是食谱,第二种是成分。食谱由以下成分组成:

    (ingredient)-[:IS_PART_OF]->(recipe)

我的目标是找出两个食谱共有多少共同成分。我已设法通过以下查询获取此信息,该查询将一个配方与所有其他配方进行比较(第一个配方与所有其他配方):

   MATCH (recipe:RECIPE{ ID: 1000000 }),(other)
   WHERE (other.ID >= 1000001 AND other.ID <= 1057690)
   OPTIONAL MATCH (recipe:RECIPE)<-[:IS_PART_OF]-(ingredient:INGREDIENT)-                 [:IS_PART_OF]->(other)
   WITH ingredient, other
   RETURN other.ID, count(distinct ingredient.name)
   ORDER BY other.ID DESC

我的第一个问题:我怎样才能获得两个食谱的所有成分的数量,而相互的只计算一次(R1和R2的并集-> R1 U R2)

我的第二个问题:是否可以编写一个循环来遍历所有食谱并检查常见成分?目标是将每个配方与所有其他配方进行比较。我认为这应该返回 (n-1)*(n/2) 行。

我已经尝试了上述方法,但问题仍然存在。即使使用LIMITSKIP,我也无法在整个集合上运行代码。我已经更改了我的查询,因此它允许我对我的集合进行相应的分区:

MATCH (recipe1)<-[:IS_PART_OF]-(ingredient:INGREDIENT)-[:IS_PART_OF]->(recipe2)
WHERE (recipe2.ID >= 1000000 AND recipe2.ID <= 1000009) AND (recipe1.ID >=   1000000 AND recipe1.ID <= 1000009) AND (recipe1.ID < recipe2.ID)
RETURN recipe1.ID, count(distinct ingredient.name) AS MutualIngredients, recipe2.ID
ORDER BY recipe1.ID

在我得到更好的机器之前,这就足够了。

我还没有解决我的第一个问题:我怎样才能以相互只计算一次的方式获得两个食谱的所有成分的数量(R1和R2的并集-> R1 U R2)

【问题讨论】:

    标签: neo4j cypher graph-databases


    【解决方案1】:

    你需要玩这个,但它会是这样的:

    MATCH (recipe1:RECIPE)<-[:IS_PART_OF]-(ingred:INGREDIENT)-[:IS_PART_OF]->(recipe2:RECIPE)
    WHERE ID(recipe1) < ID(recipe2)
    RETURN recipe1, collect(ingred.name), recipe2
    ORDER BY recipe1.ID
    

    匹配模式为您提供两个食谱之间的所有常见成分。 WHERE 子句确保您不会将配方与自身进行比较(因为它会与自己共享所有成分)。 return 子句只是为您提供要比较的两个食谱,以及它们的共同点。

    不过,这将是 O(n^2),并且会非常慢

    UPDATE 采纳了 Nicole 的建议,这是一个很好的建议。这应该保证每一对只被考虑一次。

    【讨论】:

    • 你应该添加WHERE ID(recipe1) &lt; ID(recipe2)
    • 感谢您的回答和建议。我尝试运行查询并运行了一段时间,然后有时由于 java 堆错误、GC 错误或 DB 断开连接而终止(我已在线检查,这也是一个 GC 错误)。我认为这个操作对我的电脑来说太激烈了。我尝试增加堆空间和其他一些调整,但没有成功。是否可以在不改变数据本身的情况下将操作分成几个较小的操作,仍然可以获得想要的结果?
    • 是的;使用LIMITSKIP 将此查询分解为结果的“页面”。如果你有很多食谱和配料,那么会占用大量内存也就不足为奇了。stackoverflow.com/questions/16338670/…
    • 例如,如果您的查询是 MATCH (n) RETURN n,您可以改为使用 MATCH (n) RETURN n LIMIT 10 SKIP 10,这将返回第二组 10 个结果,因此您可以将它们分成任意大小的块。
    【解决方案2】:

    已解决:仅在其他人需要时分享:

        MATCH (recipe1)<-[:IS_PART_OF]-(ingredient:INGREDIENT)-[:IS_PART_OF]->(recipe2)
        MATCH (recipe1)<-[:IS_PART_OF]-(ingredient1:INGREDIENT)
        MATCH (recipe2)<-[:IS_PART_OF]-(ingredient2:INGREDIENT)
        WHERE (recipe2.ID >= 1000000 AND recipe2.ID <= 1000009) AND (recipe1.ID >=   1000000 AND recipe1.ID <= 1000009) AND (recipe1.ID < recipe2.ID)
        RETURN recipe1.ID, count(distinct ingredient1.name) + count(distinct ingredient2.name) - count(distinct ingredient.name)  AS RecipesUnion, recipe2.ID
        ORDER BY recipe1.ID
    

    【讨论】:

      猜你喜欢
      • 2020-09-09
      • 1970-01-01
      • 2016-11-10
      • 2021-03-21
      • 1970-01-01
      • 2019-06-02
      • 2013-09-13
      • 1970-01-01
      • 2012-03-21
      相关资源
      最近更新 更多