遍历所有节点并将每个节点与每个节点进行比较

时间:2015-07-05 13:20:21

标签: neo4j cypher graph-databases

我正在开发一个小项目,我有一个大约60k节点和这些节点之间500k关系的数据集。节点有两种类型。第一类是食谱,第二类是食材。食谱由以下成分组成:

    (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)

2 个答案:

答案 0 :(得分:2)

你需要玩这个,但它会与此类似:

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的建议,这是一个很好的建议。这应该保证每对只考虑一次。

答案 1 :(得分:0)

已解决:如果其他人需要,请分享:

    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