在neo4j中将与另一个节点有关系的节点的属性继承到其子节点

时间:2017-03-01 04:21:18

标签: graph neo4j cypher

继承所有父母的属性。

考虑我有一个格式如下的图表。我希望节点的属性(将在帐户节点中,如果它有关系)由其子节点继承。假设[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

1 个答案:

答案 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中执行这种复杂的匹配操作,以实现最高效率。