Neo4j:如何将变量传递给 Neo4j Apoc (apoc.path.subgraphAll) 属性
Neo4j: How to pass a variable to Neo4j Apoc (apoc.path.subgraphAll) Property
我是 Neo4j 的新手,正在尝试通过为企业参考/集成架构(架构将所有企业应用程序显示为节点、底层表/API - 逻辑上分组为节点、应用程序之间的集成为关系)实现图数据库.
Objective 是利用 Graph DB 的力量无缝实现 'Impact Analysis'(注意:我知道这可能是实现我想要实现的任何目标的不正确方法,因此欢迎提出建议)
现在让我来简要说明一下我的问题,
有四个应用——A1、A2、A3、A4; A1 有一组表(由节点 A1TS1 表示)由集成 1(在本例中为关系)更新,集成 2 读取同一组 table。因此数据模型如下所示
(A1TS1)<-[:INT1]-(A1)<-[:INT1]-(A2)
(A1TS1)-[:INT2]->(A1)-[:INT2]->(A4)
我在 A1TS1 节点中将底层应用程序 table 名称捕获为列表 属性。
假设其中一个应用程序 table 更改为新列或数据类型,我想了解所有受影响的集成和应用程序。现在我正在尝试编写如下查询以检索所有节点和关系 associated/impacted 由于此 table 更改但我无法实现此
预期结果是 - 所有受影响的节点(A1TS1、A1、A2、A4)和关系(INT1、INT2)
选项 1(使用 APOC)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(type(r)) as allr
CALL apoc.path.subgraphAll(STRTND, {relationshipFilter:allr}) YIELD nodes, relationships
RETURN nodes, relationships
此失败错误 Failed to invoke procedure 'apoc.path.subgraphAll': Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
选项 2(使用 with、unwind、collect 子句)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(r) as allr
UNWIND allr as rels
MATCH p=()-[rels]-()-[rels]-()
RETURN p
这失败并出现错误 "Cannot use the same relationship variable 'rels' for multiple patterns" 但是如果我像 p=()-[rels]=()
那样使用 [rels] 一次,它可以工作但不会产生所有节点
任何 help/suggestion/lead 表示赞赏。提前致谢
更新
尝试提供更多背景信息
显示基础数据
MATCH (TC:TBLCON) RETURN TC
"TC"
{"Tables":["TBL1","TBL2","TBL3"],"TCName":"A1TS1","AppName":"A1"}
{"Tables":["TBL4","TBL1"],"TCName":"A2TS1","AppName":"A2"}
MATCH (A:App) RETURN A
"A"
{"Sponsor":"XY","Platform":"Oracle","TechOwnr":"VV","Version":"12","Tags":["ERP","OracleEBS","FinanceSystem"],"AppName":"A1"}
{"Sponsor":"CC","Platform":"Teradata","TechOwnr":"RZ","Tags":["EDW","DataWarehouse"],"AppName":"A2"}
MATCH ()-[r]-() RETURN distinct r.relname
"r.relname"
"FINREP" │ (runs between A1 to other apps)
"UPFRNT" │ (runs between A2 to different Salesforce App)
"INVOICE" │ (runs between A1 to other apps)
有了这个,这就是我要实现的目标
假设 "TBL3" 在应用程序 A1 中被更改,我想编写一个查询,在匹配模式中指定 table "TBL3",获取所有关联关系和连接节点(上游)
可能我需要分三步完成,
第 1 步 - 编写匹配模式以查找起始节点和关联关系
第 2 步 - 将第 1 步中的关系存储在数组变量/参数中
第 3 步 - 将第 1 步的起始节点和第 2 步的参数传递给 apoc.path.subgraphAll 以查看所有受影响的节点
这在概念上听起来可能有效,但问题是如何在 neo4j Cypher 查询中从技术上做到这一点。
希望对您有所帮助
此查询可能会执行您想要的操作:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
MATCH p=(tc)-[:Foo*]-()
WITH tc,
REDUCE(s = [], x IN COLLECT(NODES(p)) | s + x) AS ns,
REDUCE(t = [], y IN COLLECT(RELATIONSHIPS(p)) | t + y) AS rs
UNWIND ns AS n
WITH tc, rs, COLLECT(DISTINCT n) AS nodes
UNWIND rs AS rel
RETURN tc, nodes, COLLECT(DISTINCT rel) AS rels;
它假定您提供感兴趣的 table 的名称(例如,"TBL3")作为 table
parameter 的值。它还假定感兴趣的关系都具有 Foo
类型。
它首先找到 tc
,包含 table 名称的 TBLCON
个节点。然后它使用 variable-length non-directional search for all paths (with non-repeating relationships) that include tc
. It then uses COLLECT
twice: to aggregate 每个路径中的节点列表,并聚合每个路径中的关系列表。每个聚合结果将是一个列表列表,因此它在每个外部列表上使用 REDUCE
来合并内部列表。然后它在每个列表上使用 UNWIND
和 COLLECT(DISTINCT x)
来生成具有唯一元素的列表。
[更新]
如果您按类型(而不是按 属性 值)区分关系,则通过利用 APOC 函数,您的 Cypher 代码可以简单得多。以下查询假定所需的关系类型是通过 types
参数传递的:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
CALL apoc.path.subgraphAll(
tc, {relationshipFilter: apoc.text.join($types, '|')}) YIELD nodes, relationships
RETURN nodes, relationships;
根据 cybersam 的回复,下面的查询让我得到了我想要的。唯一的限制是,此结果仅限于 3 层(第 3 层通过可选匹配)
MATCH (TC:TBLCON) WHERE 'TBL3' IN TC.Tables
CALL apoc.path.subgraphAll(TC, {maxLevel:1}) YIELD nodes AS invN, relationships AS invR
WITH TC, REDUCE (tmpL=[], tmpr IN invR | tmpL+type(tmpr)) AS impR
MATCH FLP=(TC)-[]-()-[FLR]-(SL) WHERE type(FLR) IN impR
WITH FLP, TC, SL,impR
OPTIONAL MATCH SLP=(SL)-[SLR]-() WHERE type(SLR) IN impR RETURN FLP,SLP
这适合我的需要,希望这也能帮助到别人。
感谢大家的回复和建议
****更新****
增强了查询以摆脱可选匹配条件和其他给定限制
MATCH (initTC:TBLCON) WHERE $TL IN initTC.Tables
WITH Reduce(O="",OO in Reduce (I=[], II in collect(apoc.node.relationship.types(initTC)) | I+II) | O+OO+"|") as RF
MATCH (TC:TBLCON) WHERE $TL IN TC.Tables
CALL apoc.path.subgraphAll(TC,{relationshipFilter:RF}) YIELD nodes, relationships
RETURN nodes, relationships
谢谢大家(尤其是 cybersam)
我是 Neo4j 的新手,正在尝试通过为企业参考/集成架构(架构将所有企业应用程序显示为节点、底层表/API - 逻辑上分组为节点、应用程序之间的集成为关系)实现图数据库.
Objective 是利用 Graph DB 的力量无缝实现 'Impact Analysis'(注意:我知道这可能是实现我想要实现的任何目标的不正确方法,因此欢迎提出建议)
现在让我来简要说明一下我的问题,
有四个应用——A1、A2、A3、A4; A1 有一组表(由节点 A1TS1 表示)由集成 1(在本例中为关系)更新,集成 2 读取同一组 table。因此数据模型如下所示
(A1TS1)<-[:INT1]-(A1)<-[:INT1]-(A2)
(A1TS1)-[:INT2]->(A1)-[:INT2]->(A4)
我在 A1TS1 节点中将底层应用程序 table 名称捕获为列表 属性。
假设其中一个应用程序 table 更改为新列或数据类型,我想了解所有受影响的集成和应用程序。现在我正在尝试编写如下查询以检索所有节点和关系 associated/impacted 由于此 table 更改但我无法实现此
预期结果是 - 所有受影响的节点(A1TS1、A1、A2、A4)和关系(INT1、INT2)
选项 1(使用 APOC)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(type(r)) as allr
CALL apoc.path.subgraphAll(STRTND, {relationshipFilter:allr}) YIELD nodes, relationships
RETURN nodes, relationships
此失败错误 Failed to invoke procedure 'apoc.path.subgraphAll': Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
选项 2(使用 with、unwind、collect 子句)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(r) as allr
UNWIND allr as rels
MATCH p=()-[rels]-()-[rels]-()
RETURN p
这失败并出现错误 "Cannot use the same relationship variable 'rels' for multiple patterns" 但是如果我像 p=()-[rels]=()
那样使用 [rels] 一次,它可以工作但不会产生所有节点
任何 help/suggestion/lead 表示赞赏。提前致谢
更新 尝试提供更多背景信息 显示基础数据
MATCH (TC:TBLCON) RETURN TC
"TC"
{"Tables":["TBL1","TBL2","TBL3"],"TCName":"A1TS1","AppName":"A1"}
{"Tables":["TBL4","TBL1"],"TCName":"A2TS1","AppName":"A2"}
MATCH (A:App) RETURN A
"A"
{"Sponsor":"XY","Platform":"Oracle","TechOwnr":"VV","Version":"12","Tags":["ERP","OracleEBS","FinanceSystem"],"AppName":"A1"}
{"Sponsor":"CC","Platform":"Teradata","TechOwnr":"RZ","Tags":["EDW","DataWarehouse"],"AppName":"A2"}
MATCH ()-[r]-() RETURN distinct r.relname
"r.relname"
"FINREP" │ (runs between A1 to other apps)
"UPFRNT" │ (runs between A2 to different Salesforce App)
"INVOICE" │ (runs between A1 to other apps)
有了这个,这就是我要实现的目标 假设 "TBL3" 在应用程序 A1 中被更改,我想编写一个查询,在匹配模式中指定 table "TBL3",获取所有关联关系和连接节点(上游)
可能我需要分三步完成, 第 1 步 - 编写匹配模式以查找起始节点和关联关系 第 2 步 - 将第 1 步中的关系存储在数组变量/参数中 第 3 步 - 将第 1 步的起始节点和第 2 步的参数传递给 apoc.path.subgraphAll 以查看所有受影响的节点
这在概念上听起来可能有效,但问题是如何在 neo4j Cypher 查询中从技术上做到这一点。
希望对您有所帮助
此查询可能会执行您想要的操作:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
MATCH p=(tc)-[:Foo*]-()
WITH tc,
REDUCE(s = [], x IN COLLECT(NODES(p)) | s + x) AS ns,
REDUCE(t = [], y IN COLLECT(RELATIONSHIPS(p)) | t + y) AS rs
UNWIND ns AS n
WITH tc, rs, COLLECT(DISTINCT n) AS nodes
UNWIND rs AS rel
RETURN tc, nodes, COLLECT(DISTINCT rel) AS rels;
它假定您提供感兴趣的 table 的名称(例如,"TBL3")作为 table
parameter 的值。它还假定感兴趣的关系都具有 Foo
类型。
它首先找到 tc
,包含 table 名称的 TBLCON
个节点。然后它使用 variable-length non-directional search for all paths (with non-repeating relationships) that include tc
. It then uses COLLECT
twice: to aggregate 每个路径中的节点列表,并聚合每个路径中的关系列表。每个聚合结果将是一个列表列表,因此它在每个外部列表上使用 REDUCE
来合并内部列表。然后它在每个列表上使用 UNWIND
和 COLLECT(DISTINCT x)
来生成具有唯一元素的列表。
[更新]
如果您按类型(而不是按 属性 值)区分关系,则通过利用 APOC 函数,您的 Cypher 代码可以简单得多。以下查询假定所需的关系类型是通过 types
参数传递的:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
CALL apoc.path.subgraphAll(
tc, {relationshipFilter: apoc.text.join($types, '|')}) YIELD nodes, relationships
RETURN nodes, relationships;
根据 cybersam 的回复,下面的查询让我得到了我想要的。唯一的限制是,此结果仅限于 3 层(第 3 层通过可选匹配)
MATCH (TC:TBLCON) WHERE 'TBL3' IN TC.Tables
CALL apoc.path.subgraphAll(TC, {maxLevel:1}) YIELD nodes AS invN, relationships AS invR
WITH TC, REDUCE (tmpL=[], tmpr IN invR | tmpL+type(tmpr)) AS impR
MATCH FLP=(TC)-[]-()-[FLR]-(SL) WHERE type(FLR) IN impR
WITH FLP, TC, SL,impR
OPTIONAL MATCH SLP=(SL)-[SLR]-() WHERE type(SLR) IN impR RETURN FLP,SLP
这适合我的需要,希望这也能帮助到别人。
感谢大家的回复和建议
****更新****
增强了查询以摆脱可选匹配条件和其他给定限制
MATCH (initTC:TBLCON) WHERE $TL IN initTC.Tables
WITH Reduce(O="",OO in Reduce (I=[], II in collect(apoc.node.relationship.types(initTC)) | I+II) | O+OO+"|") as RF
MATCH (TC:TBLCON) WHERE $TL IN TC.Tables
CALL apoc.path.subgraphAll(TC,{relationshipFilter:RF}) YIELD nodes, relationships
RETURN nodes, relationships
谢谢大家(尤其是 cybersam)