首页 > 解决方案 > 在 Cypher 中获取具有特定类型的恰好一个关系的节点对,这些关系将它们相互连接

问题描述

我在 Neo4j 中有一个图形数据库,其中包含药物和药物-药物相互作用等实体。在这方面,()-[:IS_PARTICIPANT_IN]->()将药物与相互作用联系起来。我需要获得那些药物对,a它们除了它们之间的关系之外b不涉及任何其他:IS_PARTICIPANT_IN关系,即(a)-[:IS_PARTICIPANT_IN]->(ddi:DrugDrugInteraction)<-[:IS_PARTICIPANT_IN]-(b)没有任何其他IS_PARTICIPANT_IN关系,既不涉及a也不涉及b

为此,我尝试了以下 Cypher 查询。但是,它最终会达到堆大小(增加到 8 GB),因为收集操作会消耗太多内存。

MATCH (drug1:Drug)-[r1:IS_PARTICIPANT_IN]->(ddi:DrugDrugInteraction)
MATCH (drug2:Drug)-[r2:IS_PARTICIPANT_IN]->(ddi)
WHERE drug1 <> drug2 
OPTIONAL MATCH (drug2)-[r3:IS_PARTICIPANT_IN]->(furtherDDI:DrugDrugInteraction)
WHERE furtherDDI <> ddi
WITH drug1, drug2, ddi, COLLECT(ddi) AS ddis, furtherDDI, COLLECT(furtherDDI) AS additionalDDIs
WITH drug1, drug2, ddi, COUNT(ddis) AS n1, COUNT(additionalDDIs) AS n2
WHERE n1 = 1 AND n2 = 0
RETURN drug1.name, drug2.name, ddi.name ORDER BY drug1;

如何在不超过堆大小限制的情况下改进我的代码以获得所需的结果?

标签: neo4jcypher

解决方案


这应该有效:

MATCH (d:Drug)
WHERE SIZE((d)-[:IS_PARTICIPANT_IN]->()) = 1
MATCH (d)-[:IS_PARTICIPANT_IN]->(ddi)
RETURN ddi.name AS ddiName, COLLECT(d.name) AS drugNames
ORDER BY drugNames[0]

WHERE子句使用非常有效的度数检查来过滤Drug只有一个传出IS_PARTICIPANT_IN关系的节点。这种检查是有效的,因为它不必实际获取任何DrugDrugInteraction节点。

在度数检查之后,查询会执行一秒钟MATCH以实际获取关联DrugDrugInteraction节点。(我假设IS_PARTICIPANT_IN关系只指向DrugDrugInteraction节点,因此为了提高效率,从搜索模式中省略了标签)。

RETURN子句使用聚合函数 COLLECT来收集Drug每个名称的ddi名称。(我假设ddi节点具有唯一的名称。)

顺便说一句,如果有任意数量的Drugs(不仅仅是 2 个)参与相同的 s DrugDrugInteraction,并且没有其他的,这个查询也将起作用。此外,如果匹配项DrugDrugInteraction碰巧有Drug参与其他交互的相关项,则此查询不会将其包含Drug在结果中(因为此查询仅关注d通过初始度数检查的节点)。


推荐阅读