有没有一种方法可以使用Cypher遍历neo4j路径以实现不同的关系

时间:2018-12-29 17:54:34

标签: neo4j cypher

我想遍历neo4j中的PATH(最好使用Cypher,但我可以编写neo4j托管扩展)。

问题- 对于任何起始节点(:Person),我都想遍历

之类的层次结构

(我:人)-[:朋友|:知识*]->(新人:人)

如果存在:FRIEND外向关系,则路径应遍历该路径,并忽略任何:KNOWS外向关系;如果:FRIEND关系不存在,但:KNOWS关系存在,则PATH应该遍历该节点。

现在,上面语法的问题是它同时返回了带有:FRIEND和:KNOWS的路径-我无法根据上述要求滤除特定方向。

3 个答案:

答案 0 :(得分:1)

1。数据集示例

为便于进一步解答和解决方案,我注意到了我的图形创建语句:

CREATE
  (personA:Person {name:'Person A'})-[:FRIEND]->(personB:Person {name: 'Person B'}),
  (personB)-[:FRIEND]->(personC:Person {name: 'Person C'}),
  (personC)-[:FRIEND]->(personD:Person {name: 'Person D'}),
  (personC)-[:FRIEND]->(personE:Person {name: 'Person E'}),
  (personE)-[:FRIEND]->(personF:Person {name: 'Person F'}),
  (personA)-[:KNOWS]->(personG:Person {name: 'Person G'}),
  (personA)-[:KNOWS]->(personH:Person {name: 'Person H'}),
  (personH)-[:KNOWS]->(personI:Person {name: 'Person I'}),
  (personI)-[:FRIEND]->(personJ:Person {name: 'Person J'});

graph 1

2。方案“可选匹配”

2.1解决方案

MATCH (startNode:Person {name:'Person A'})
OPTIONAL MATCH friendPath = (startNode)-[:FRIEND*]->(:Person)
OPTIONAL MATCH knowsPath = (startNode)-[:KNOWS*]->(:Person)
RETURN friendPath, knowsPath;

如果您不需要到达整个路径的所有节点的每个路径,而只需要整个路径,那么出于性能原因,我建议使用shortestPath()

2.1结果

请注意缺少的节点“ Person J”,因为它与节点“ Person I”具有FRIENDS关系。

graph 2

3。方案“扩展路径”

3.1解决方案

或者,您可以使用Expand pathsAPOC user library函数。根据过程的下一步,您可以在节点,关系或两者的标识之间进行选择。

MATCH (startNode:Person {name:'Person A'})
CALL apoc.path.subgraphNodes(startNode,
  {maxLevel: -1, relationshipFilter: 'FRIEND>', labelFilter: '+Person'}) YIELD node AS friendNodes
CALL apoc.path.subgraphNodes(startNode,
  {maxLevel: -1, relationshipFilter: 'KNOWS>', labelFilter: '+Person'}) YIELD node AS knowsNodes
WITH
  collect(DISTINCT friendNodes.name) AS friendNodes,
  collect(DISTINCT knowsNodes.name) AS knowsNodes
RETURN friendNodes, knowsNodes;

3.2解释

  • 第1行:根据名称定义起始节点
  • 第2-3行:遵循标签过滤器(startNode)上的给定关系(relationshipFilter: 'FRIEND>')从给定的labelFilter: '+Person'展开。
  • 第4-5行:遵循标签过滤器(startNode)上的给定关系(relationshipFilter: 'KNOWS>')从给定的labelFilter: '+Person'展开。
  • 第7行:按照FRIEND关系类型聚合所有节点(如果需要完整的节点,请省略.name部分)
  • 第8行:按照KNOWS关系类型聚合所有节点(如果需要完整的节点,请省略.name部分)
  • 第9行:渲染结果的节点组

3.3结果

╒═════════════════════════════════════════════╤═════════════════════════════════════════════╕
│"friendNodes"                                │"knowsNodes"                                 │
╞═════════════════════════════════════════════╪═════════════════════════════════════════════╡
│["Person A","Person B","Person C","Person E",│["Person A","Person H","Person G","Person I"]│
│"Person D","Person F"]                       │                                             │
└─────────────────────────────────────────────┴─────────────────────────────────────────────┘

答案 1 :(得分:0)

MATCH p = (me:Person)-[:FRIEND|:KNOWS*]->(newPerson:Person) 
WITH p, extract(r in relationships(p) | type(r)) AS types
RETURN p ORDER BY types asc LIMIT 1

答案 2 :(得分:0)

这是询问每个节点的传出关系的类型,然后根据一些嵌套的案例逻辑优先确定要保留哪些关系的问题。

使用上面的小图

MATCH path = (a)-[r:KNOWS|FRIEND]->(b) WITH a, COLLECT([type(r),a,r,b]) AS rels WITH a, rels, CASE WHEN filter(el in rels WHERE el[0] = "FRIEND") THEN filter(el in rels WHERE el[0] = "FRIEND") ELSE CASE WHEN filter(el in rels WHERE el[0] = "KNOWS") THEN filter(el in rels WHERE el[0] = "KNOWS") ELSE [''] END END AS search UNWIND search AS s RETURN s[1] AS a, s[2] AS r, s[3] AS b

我相信这会返回您的预期结果:

enter image description here

根据您的逻辑,不应从人A到人G或人H遍历,因为从人A到人B的朋友关系优先。

但是,由于存在奇异的KNOWS关系,因此从人H到人I进行遍历,然后又从人I到人J进行遍历。