在Neo4j中从与另一个节点有关系的节点继承其子节点的属性 [英] Inherit properties from a node with relationship to another node to its child in neo4j
问题描述
从所有父级继承属性.
考虑一下,我有一个下面格式的图.我希望节点的属性(如果有关系,将在帐户节点中)由其子节点继承.假设父级和子级节点关系由[r:CHILD]维护,帐户信息由[r2:ACCOUNT]维护.如果节点有多个父节点,则需要使用第一个帐户从其所有父节点继承:
Consider I have a graph with below format. I want the properties of a node (which will be in account node, if it has a relation) to be inherited by its child node. Assume Parent and child node relationship is maintained by [r:CHILD] and account information by [r2:ACCOUNT]. If node has more than one parent, it needs to inherit from all its parent with the first 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
我想从上面的图中提取数据,如下所示:
I want to extract the data from the above graph something like this:
问题:给定一个节点,获取其所有子节点以及其帐户(如果它具有account,例如:参见节点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 |
- - - - - -- - - - - -- - - - - -- - - - - -- - - - -
这是我想出的密码,可让我获得所有父母的所有账目.有时不起作用
This was my cypher to retrive that I came up with, gets me all the accounts of all the parents. It doesnt work sometimes
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
推荐答案
这是一个棘手的问题.
存在一个纯Cypher解决方案,但这是一个复杂的查询,并且需要一些潜在的繁重过滤才能清除通往同一帐户中距离更近的帐户持有节点的帐户持有节点的路径.
A pure Cypher solution exists, but it's a complicated query and requires some potentially heavy filtering to weed out paths to account-holding nodes that are beyond closer account-holding nodes along the same path.
但是,我发现使用Cypher和 APOC的路径可以找到更好的选择扩展器,以及将标签添加到帐户持有者的节点上的一些预处理.
However, I've found a better alternate using Cypher and APOC's path expander, plus some pre-processing of adding a label to nodes that are account holders.
APOC的路径扩展器具有一种在遵守标签过滤器的同时进行扩展的方法,并且有一种方法可以定义应修剪任何进一步遍历但作为解决方案包括在内的标签.当获得节点的帐户持有祖先时,我们将使用它来限制扩展.
APOC's path expander has a means of expanding while respecting a label filter, and there is a means to define a label which should prune any further traversal, but be included as a solution. We'll use this to limit our expansion when getting account-holding ancestors for nodes.
这是一个创建查询,用于在您的示例中重新创建图(尽管我将非ACCOUNT节点标记为:Node):
Here's a creation query to recreate the graph in your example (though I'm labeling non-ACCOUNT nodes as :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'})
接下来,我们标记帐户持有节点.
Next, we label account-holding nodes.
MATCH (acc:ACCOUNT)
WITH acc
MATCH (acc)<-[:HAS_ACCOUNT]-(holder)
SET holder:ACCOUNT_HOLDER
到位后,我们可以使用以下查询来获取所需的输出:
Once that's in place, we can use the following query to get your desired output:
// 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的方式执行此复杂的匹配操作,以实现最高效率.
However, note that even with this approach, the query will not build up and reuse solutions (for example, once we've found the account-holding ancestors for node A, that solution is not referenced or reused when we have to get the account-holding ancestors for nodes, C, F, or G). You may want to consider a custom procedure to perform this complicated matching operation in code rather than Cypher for maximum efficiency.
这篇关于在Neo4j中从与另一个节点有关系的节点继承其子节点的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!