[英]Nested unions in Cypher/Neo4j
我在 Neo4j 中有这个元图:
:Protein ---> :is_a ---------------> :Enzyme ---> :activated_by|inhibited_by ---> :Compound
\<-- :activated_by <---/
:Compound --> :consumed_by|:produced_by ---> :Transport
\<---- :catalyzed_by -------<---/
:Transport --> part_of ---> :Pathway
(是的,它是生物学的,是的,它是从 BioPAX 进口的)。
我想使用 Cypher 返回由某个图形路径链接的所有(:Protein, :Compounds)
对。 虽然一种简单的方法是遵循两种节点类型之间的每个可能路径并为每个节点发出一个查询,但显然使用某种模式联合的查询会更紧凑(可能更慢,我正在评估不同方法的性能) .
但是如何编写这样的查询呢? 我读过 Cypher 有一个 UNION 结构,但我不清楚如何组合和嵌套它们,例如,关于从酶到运输的子图,我希望能够写出与这个非正式表达式等效的东西:
enz:Enzyme :activated|inhibited_by comp:Compund
join with: (
(comp :consumed_by|produced_by :Transport)
UNION (:Transport :catalyzed_by comp )
)
我读过应该有一些方法,但我没有得到太多,我试图了解是否有一种相对简单的方法(在 SPARQL 或 SQL 中,上述方法相当简单)。
在 Cypher 中,您可以使用 WITH 将查询分解为多个步骤,并且可以通过将两个列表连接在一起来连接它们。
MATCH (e:Enzyme)-[:activated]->(compA:Compound), (e)-[:inhibited_by]->(compB:Compund)
WITH e, COLLECT(compA)+COLLECT(compB) as compList
UNWIND compList as comp
WITH DISTINCT e, comp // if a comp can appear in both lists
MATCH ... // Repeat above at each path step
当使用 Union 组合不同的查询时,可以把它想象成一个逗号分隔的查询列表,但不是逗号,而是使用 UNION 这个词(此外,这个列表中的每个查询都必须具有相同的返回列。
MATCH (e:Enzyme)-[r1:activated]->(comp:Compound)-[r2:consumed_by]->(trans:Transport)
RETURN e as protein, comp as compound, trans as transport
UNION
MATCH (e:Enzyme)-[r1:inhibited_by]->(comp:Compound)-[r2:produced_by]->(trans:Transport)
RETURN e as protein, comp as compound, trans as transport
// Just to show only return names have to match
UNION
WITH "rawr" as a
RETURN a as protein, 51 as compound, NULL as transport
这对于组合完全不同的查询的结果很有好处,但由于您正在组合的查询通常是相关的,因此在大多数情况下 COLLECT 会更有效,并且可以让您更好地控制结果。
您可以使用 TYPE 函数获取关系的名称并对其进行过滤。
MATCH (e:Enzyme)-[r1]->(comp:Compound)-[r2]->(trans:Transport)
WHERE (TYPE(r1) = "activated" OR TYPE(r1) = "inhibited_by") AND (TYPE(r2) = "consumed_by" OR TYPE(r2) = "produced_by")
RETURN *
注意:要仅对它们的关系类型使用 OR,您也可以使用-[:A|:B]->
来表示 OR。
从 Neo4j 3.1.x 开始,Cypher 非常擅长自由路径查找。 (我的意思是在不搜索所有可能路径的情况下找到有效路径。 关系匹配的模式)上限不是绝对必要的,但对于防止/控制失控查询很有用。
MATCH p=(e:Protein)-[r1*..10]->(c:Compound)
WHERE ALL(r in RELATIONSHIPS(p) WHERE TYPE(r) in ["activated","inhibited_by","produced_by","consumed_by"])
RETURN e as protein, c as compound
(e:Enzyme)-->(c:Compound)
或忽略方向(e:Enzyme)--(c:Compound)
下面的查询将返回由Transport
消耗、产生或催化的Compound
激活或抑制Enzyme
所有路径。
查询的r2
的关系模式是无方向性的,因为的方向性catalyzed_by
是,相对consumed_by
和produced_by
。
MATCH p=
(e:Enzyme)-[r1:activated_by|:inhibited_by]->
(comp:Compound)-[r2:consumed_by|:produced_by|:catalyzed_by]-
(trans:Transport)
RETURN p;
所以,我还没有找到一种令人满意的方法来做我最初要求的事情,但我已经很接近它了,我想报告一下。
首先,我的初始图表与我实际拥有的图表略有不同,因此我将下一个示例基于真实的示例(抱歉造成混淆):
我可以很轻松地使用 WHERE 子句中的路径来处理分支(在更简单的情况下,还有 UNIONS):
// Branch 2 MATCH (prot:Protein), (enz:Enzyme), (tns:Transport) - [:part_of] -> (path:Path) WHERE ( (enz) - [:ac_by|:in_by] -> (:Comp) - [:pd_by|:cs_by] -> (tns) // Branch 2.1 OR (tns) - [:ca_by] -> (enz) ) //Branch 2.2 (pt1)
AND ( (prot) - [:is_a] -> (enz) OR (prot) <- [:ac_by] - (enz) ) // Branch 2.2 (pt2) RETURN prot, path LIMIT 30 UNION // Branch1 MATCH (prot:Protein) - [:pd_by|:cs_by] -> (:Reaction) - [:part_of] -> (path:Path) RETURN prot, path LIMIT 30
(我也为所有这些缩写感到抱歉,例如,pd_by 是生产者_by,ac_by 是激活_比等等)。
此查询在大约 1 分钟内产生结果。 太长了,这显然是由于查询的解释方式,正如从其计划中可以看出的:
我真的不明白为什么会有那些巨大的笛卡尔积。 我已经尝试了 WITH/UNWIND 方法,但我一直无法得到正确的结果(见我上面的评论,感谢 @Tezra 和 @cybersam),即使我是,这是一个非常困难的语法。
@zakmck或其他任何人,我有一个基本问题-如何将BioPAX猫头鹰文件导入Neo4j?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.