首页 > 解决方案 > 联合查询后如何获取交集

问题描述

我正在开发一个使用 neo4j 图形数据库的项目。我正在构建一个用户界面,该界面生成一个密码查询以从图形数据库中检索一些结果。基本上,我有患者参与程序,这些程序有数字结果。这个想法是用户可以选择不同的程序,例如“Pa”、“Pb”和“Pc”,也可以通过它们的结果来限制它们;例如“Pa”的结果应该在2到7之间。然后,应该提取满足要求的患者。

为此,我为每个过程生成一个通用查询,然后,我使用“联合”来将所有内容放在一起。例如(非常简化,因为我的数据模型更复杂):

MATCH (patient:Patient) 
WITH patient 
CALL { 
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pa`)-[:`hasResult`]->(result:`ResultValue`)
WHERE (result.hasValue >= 2 AND result.hasValue <= 7 ) 
RETURN DISTINCT patient as patient_inner, procedure, result 

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pb`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result 

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pc`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result

}

RETURN DISTINCT patient.label, procedure.label, result.hasValue

此查询可能有以下结果,其中包括所有参与“Pb”或“Pc”或“Pa”的患者,结果介于 2 和 7 之间,因为 UNION 意味着 OR: 查询结果

尽管如此,我想允许一个 AND 连接,以检索所有参与“Pb”和“Pc”和“Pa”的患者,结果在 2 到 7 之间。

所以,我想要删除患者 2 和患者 3,因为它们不符合“和”条件。

我发现的第一个问题是联合之后所有的东西都被合并了,我不知道哪一行来自什么查询。我不能使用过程列,因为用户可以多次选择相同的过程以包含不同的限制,这被翻译成具有相同过程的多个联合。我可以通过在每个联合查询中包含一个常量来克服这个问题,如下所示:

MATCH (patient:Patient) 
WITH patient 
CALL { 
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pa`)-[:`hasResult`]->(result:`ResultValue`)
WHERE (result.hasValue >= 2 AND result.hasValue <= 7 ) 
RETURN DISTINCT patient as patient_inner, procedure, result, 'id1' as id

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pb`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result 'id2' as id

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pc`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result, 'id3' as id

}

RETURN DISTINCT patient.label, procedure.label, result.hasValue, id

结果: 查询结果2

有了这个,我可以收集每个患者的 id,并只保留那些具有“id1”、“id2”和“id3”的患者:

MATCH (patient:Patient) 
WITH patient 
CALL { 
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pa`)-[:`hasResult`]->(result:`ResultValue`)
WHERE (result.hasValue >= 2 AND result.hasValue <= 7 ) 
RETURN DISTINCT patient as patient_inner, procedure, result, 'id1' as id

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pb`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result 'id2' as id

UNION
  
WITH patient 
MATCH (patient)-[:`isParticipantIn`]->(procedure:`Pc`)-[:`hasResult`]->(result:`ResultValue`)
RETURN DISTINCT patient as patient_inner, procedure, result, 'id3' as id

}

WITH patient, collect(id) as ids
WHERE all(x in ['p1', 'p2', 'p3'] WHERE x IN ids)
RETURN patient

查询返回了 patient1,这是正确的。但是,在这里我错过了该患者的程序和结果。我不能在 WITH 子句中包含过程和结果变量,因为它会修改 id 的分组。我也尝试收集和展开这些变量,但我认为 neo4j 在展开操作后不知道如何关联它们,从而创建笛卡尔积。此外,我认为我不能使用与 id 匹配的图形模式,因为 id 是人为包含的并且它不是节点,并且可能与结果表之外的患者节点无关。

我一直在调查自定义程序,但我发现了类似的问题。例如,如果该过程接收到一个节点列表,我必须在调用它之前收集它们,这会导致我之前描述的问题。此外,如果该过程接收单个节点,它将在结果中的每个节点执行一次,并且我没有关于其他节点的信息以便在内部进行分组。我不太确定是否可以定义一个以结果集作为输入的过程,以及您要用于分组和收集的列,以便执行您想做的任何事情。

这有什么线索吗?我可以通过处理我显示的第一个查询的结果来处理这个问题,但我更愿意在单个查询中拥有这种行为,而不必手动操作结果。

预先感谢。

标签: neo4jcypher

解决方案


经过几天的努力解决这个问题,我无法在查询中解决它,所以我不得不在我的应用程序代码中对查询结果进行后处理。

我要关闭它是因为我认为我想做的事情在 Cypher 中是不可能的。


推荐阅读