首页 文章

Cypher / Neo4j中的嵌套联盟

提问于
浏览
0

我在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 )
)

我读过there should be some way,但是我没有试图理解是否有一种相对简单的方法(在SPARQL或SQL中,上面的内容相当简单) .

3 回答

  • 0

    使用定期收集

    在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来组合不同的查询时,可以将它想象成逗号分隔的查询列表,而不是逗号,而是使用单词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将更有效,并且可以更好地控制结果 .

    使用OR

    您可以使用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相当擅长自由寻路 . (通过这种方式,我的意思是找到一个有效的路径而不搜索所有可能的路径._783306的模式)上限不是严格必要的,但对于防止/控制失控查询很有用 .

    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)

    • 如果是一个选项,我建议重构您的模式以使其更加一致(或添加与此匹配条件相关的关系类型),这样您就不需要联合结果 . (这将为您提供最佳性能,因为Cypher规划人员将更好地了解如何快速找到您的结果)

  • 1

    下面的查询将返回 EnzymeTransport 消耗,生成或催化的 Compound 激活或禁止的所有路径 .

    查询的 r2 关系模式是非方向性的,因为 catalyzed_by 的方向性与 consumed_byproduced_by 的方向性相反 .

    MATCH p=
      (e:Enzyme)-[r1:activated_by|:inhibited_by]->
      (comp:Compound)-[r2:consumed_by|:produced_by|:catalyzed_by]-
      (trans:Transport)
    RETURN p;
    
  • 0

    所以,我还没有找到一个令人满意的方式来做我最初的要求,但我非常接近它,我想报告一下 .

    首先,我的初始图形与我实际的图形略有不同,因此我将基于真实图形的下一个示例(抱歉混淆):

    enter image description here

    我可以使用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是produ_by,ac_by是activate_by等等) .

    该查询在大约1分钟内产生结果 . 太长了,这显然是由于查询的解释方式,正如人们从其计划中可以看到的那样:

    enter image description here

    我真的不明白为什么会有那些巨大的笛卡尔产品 . 我尝试过WITH / UNWIND方法,但是我无法得到正确的结果(请参阅上面的评论,感谢@Tezra和@cybersam),即使我是,也是一个非常困难的语法 .

相关问题