继承所有父母的属性。
考虑我有一个格式如下的图表。我希望节点的属性(将在帐户节点中,如果它有关系)由其子节点继承。假设[r:CHILD]维护父节点和子节点关系,[r2:ACCOUNT]维护帐户信息。如果节点有多个父节点,则需要使用第一个帐户从其所有父节点继承:
(a0:ACCOUNT)<-[:HAS_ACCOUNT]-Morpheus
\
(a1:ACCOUNT)<-[:HAS_ACCOUNT]-Neo
\
alpha
\
gamma beta - [:HAS_ACCOUNT]->(a2:ACCOUNT)
\ /
A
/ \
(a3:ACCOUNT)<-[:HAS_ACCOUNT]-B C
/ \ / \
D E F G
我想从上面的图中提取数据:
问题:给定一个节点,获取其所有子节点及其帐户(如果有帐户,例如:参见节点B)或其继承的帐户信息。 AccountID是帐户节点的一部分
考虑输入是节点A
输出:
|Node | CurrentNode| Account |Inherited_Account|
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | A | - | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | B | a3.accountID | - |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | D | | a3.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | E | | a3.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | C | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | F | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
| A | G | | a1.accountID ,|
| | | | a2.accountID |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
这是我想要追溯的密码,我得到了所有父母的所有帐户。它有时不起作用
MATCH (node:Person{personID:"A"})
MATCH (account:ACCOUNT)
MATCH p =(parent:Person)-[:CHILD*1..]->(node)
where (parent)-[:HAS_ACCOUNT]->(account)
UNWIND RELATIONSHIPS(p) AS rel
WITH p, account, COUNT(DISTINCT rel) AS nRoutes
RETURN account,p, nRoutes
ORDER BY nRoutes
答案 0 :(得分:0)
这是一个棘手的问题。
存在纯粹的Cypher解决方案,但这是一个复杂的查询,需要进行一些潜在的大量过滤来清除帐户持有节点的路径,这些节点沿着相同的路径超越了更紧密的帐户持有节点。
但是,我找到了一个使用Cypher和APOC's path expander的更好的替代方案,以及一些为帐户持有者添加标签的预处理。
APOC的路径扩展器有一种在尊重标签过滤器的同时进行扩展的方法,并且有一种方法可以定义一个标签,该标签应该修剪任何进一步的遍历,但作为解决方案包括在内。在获取节点的帐户持有祖先时,我们将使用它来限制我们的扩展。
这是一个创建查询,用于在示例中重新创建图形(尽管我将非ACCOUNT节点标记为:Node):
// create inherited account graph
create (morpheus:Node{name:'Morpheus'})
create (neo:Node{name:'Neo'})
create (alpha:Node{name:'alpha'})
create (gamma:Node{name:'gamma'})
create (beta:Node{name:'beta'})
create (A:Node{name:'A'})
create (B:Node{name:'B'})
create (C:Node{name:'C'})
create (D:Node{name:'D'})
create (E:Node{name:'E'})
create (F:Node{name:'F'})
create (G:Node{name:'G'})
create (morpheus)-[:CHILD]->(neo)
create (neo)-[:CHILD]->(alpha)
create (alpha)-[:CHILD]->(gamma)
create (gamma)-[:CHILD]->(A)
create (beta)-[:CHILD]->(A)
create (A)-[:CHILD]->(B)
create (A)-[:CHILD]->(C)
create (B)-[:CHILD]->(D)
create (B)-[:CHILD]->(E)
create (C)-[:CHILD]->(F)
create (C)-[:CHILD]->(G)
create (morpheus)-[:HAS_ACCOUNT]->(a0:ACCOUNT{name:'a0'})
create (neo)-[:HAS_ACCOUNT]->(a1:ACCOUNT{name:'a1'})
create (beta)-[:HAS_ACCOUNT]->(a2:ACCOUNT{name:'a2'})
create (B)-[:HAS_ACCOUNT]->(a3:ACCOUNT{name:'a3'})
接下来,我们标记帐户持有节点。
MATCH (acc:ACCOUNT)
WITH acc
MATCH (acc)<-[:HAS_ACCOUNT]-(holder)
SET holder:ACCOUNT_HOLDER
一旦到位,我们可以使用以下查询来获得您想要的输出:
// parameterize this in your own query
with 'A' as nodeName
match (node:Node{name:nodeName})-[r:CHILD*0..]->(currentNode)
with node, currentNode, size(r) as distance
optional match (currentNode)-[:HAS_ACCOUNT]->(acc)
with node, currentNode, distance, collect(acc) as accounts
// we now have all child nodes of the given node and their accounts, if they exist.
// this expands up from each currentNode,
// stopping each expansion at the closest ACCOUNT_HOLDER node
call apoc.path.expand(currentNode, '<CHILD', '/ACCOUNT_HOLDER', -1, -1)
yield path
with node, currentNode, distance, accounts, last(nodes(path)) as holder
// get the account for each holder,
// but only if the current doesn't have its own accounts
optional match (holder)-[:HAS_ACCOUNT]->(acc)
where size(accounts) = 0
with node, currentNode, accounts, collect(acc) as inherited, distance
order by distance asc
return node, currentNode, accounts, inherited
但是,请注意,即使采用这种方法,查询也不会构建和重用解决方案(例如,一旦我们找到了节点A的帐户持有祖先,当我们必须时,该解决方案不被引用或重用)获取节点,C,F或G的帐户持有祖先。您可能需要考虑一个自定义过程来在代码而不是Cypher中执行这种复杂的匹配操作,以实现最高效率。