获取每个关系深度

时间:2017-10-05 15:54:08

标签: neo4j cypher

我正在开发一个项目,其中每个用户都被表示为Neo4j中的一个节点。用户可以“认可”其他用户,建立关系。我希望能够根据用户的信任对用户进行排名,其中每个关系的权重取决于支持他们的用户的权重。例如,已经被20多个用户认可的用户应该比仅拥有几个代言的其他用户拥有更多自己的代言权。

我现在查询它的方式为我提供了每个深度的节点数,但它没有按父节点分组(例如,所有3级节点都在一个数组中返回,你不知道哪个级别2的节点各自相关)。

MATCH (n)-[r:TRUSTS*]->(u)
WHERE u.name = 'XYZ' WITH n.name AS n, LENGTH(r) AS depth
RETURN COLLECT(DISTINCT n) AS endorsers, depth
ORDER BY depth

这是网络的样子,以及Ben的查询结果。

enter image description here enter image description here

正如您所看到的,Ben有两个第一级代言人,JM有两个二级代言人,您可以从图表图片中看到,但不能从查询结果中看到

任何人都可以建议如何返回按父节点和深度分组的结果,这样我可以计算代码中的信任排名,或者更好的方法来执行加权平均来实现第一段中的目标? / p>

这是我想象的那种树结构输出的例子:

Ben
├── JM
│   ├── Simon
│   └── Rus
│       ├── Robbie
│       │   ├── Ben
│       │   │   └──/ should terminate here
│       │   ├── Simon
│       │   └── JM
│       └── Ben
│           └──/ should terminate here
└── Simon

这是罗斯的另一个:

Rus
├── Robbie
│   ├── Simon
│   ├── Ben
│   │   ├── Simon
│   │   └── JM
│   │       ├── Simon
│   │       └── Rus
│   └── JM  
│       ├── Simon
│       └── Rus            
└── Ben
    ├── Simon
    └── JM
        ├── Simon
        └── Rus

显然它应该在它到达我正在查询的用户时终止(否则它将是一个循环结构)。

我找到的最接近的匹配是Tezra提供的查询,即:

MATCH (target:User{name:"Rus"}), (person:User), p=((person)-[:TRUSTS*]->(target))
WHERE ALL(n in NODES(p)[1..-1] WHERE n<>target)
RETURN NODES(p)[-2].name as endorser, COLLECT(person.name) as endorsed_by, SIZE(RELATIONSHIPS(p)) as depth
ORDER BY depth

此查询返回“Rus”的第一级代言人,然后是n级代言人第一级代言人:

| endorser | endorsed_by           | depth |
|----------|-----------------------|-------|
| Robbie   | Robbie                | 1     | // 1st level endorsers of Rus
| Ben      | Ben                   | 1     | // 1st level endorsers of Rus

| Robbie   | JM, Simon, Ben        | 2     | // 1st level endorsers of Robbie
| Ben      | JM, Simon             | 2     | // 1st level endorsers of Ben

| Ben      | Rus, Simon            | 3     | // 2nd level endorsers of Ben
| Robbie   | Rus, Simon, JM, Simon | 3     | // 2nd level endorsers of Robbie

| Robbie   | Rus, Simon            | 4     | // 3rd level endorsers of Robbie

这不太正确,你只知道谁间接支持Ben和Robbie,而不是其间的节点。

例如,从该输出中我们知道Robbie的第一级代言人是JMSimonBen。第二级代言人是RusSimonJMSimon(树中的第4列),但是无法知道第1级和第2级之间的关系级别代言人。就此查询而言,以下树是相同的:

Rus
└── Robbie
    ├── Simon
    ├── Ben         <--- here Ben has 3 children (so should be weighted higher)
    │   ├── Simon
    │   ├── Rus
    │   └── JM
    └── JM
        └── Simon 


Rus
└── Robbie
    ├── Simon
    ├── Ben
    │   └── Simon
    └── JM          <--- here JM has 3 children instead
        ├── Simon     
        ├── Rus
        └── JM       

我正在寻找的是一个返回类似这样的东西的查询(每个代言的父代都可以重建完整的树),这是Rus的想象输出:

+--------+----------+-------+
| parent | children | depth |
+--------+----------+-------+
| Rus    | Robbie   | 1     |
+--------+----------+-------+
| Rus    | Ben      | 1     |
+--------+----------+-------+
| Robbie | Simon    | 2     |
+--------+----------+-------+
| Robbie | Ben      | 2     |
+--------+----------+-------+
| Robbie | JM       | 2     |
+--------+----------+-------+
| Ben    | Simon    | 3     |
+--------+----------+-------+
| Ben    | JM       | 3     |
+--------+----------+-------+
| JM     | Simon    | 4     |
+--------+----------+-------+
| JM     | Rus      | 4     |
+--------+----------+-------+
| JM     | Simon    | 3     |
+--------+----------+-------+
| JM     | Rus      | 3     |
+--------+----------+-------+
| Ben    | Simon    | 2     |
+--------+----------+-------+
| Ben    | JM       | 2     |
+--------+----------+-------+
| JM     | Simon    | 3     |
+--------+----------+-------+
| JM     | Rus      | 3     |
+--------+----------+-------+

1 个答案:

答案 0 :(得分:2)

首先,这是一个console来播放/测试数据。

以下是一些评论过的查询。让我知道哪个最符合您的需求。 (按相关性排序)

// Match the query target, and everyone who can endorse
MATCH (target:User{name:"Ben"}), (person:User),

// Match all endorse chains, length limit 5 
p=((person)-[:TRUSTS*..5]->(target)) 

// Our target may start, and will end; our chain, so no other path nodes can be him. 
// Normal matching will not match cycles.
// Adjust further path termination conditions here.
WHERE ALL(n in NODES(p)[1..-1] WHERE n<>target) 

//  Return target (extra), the 1'st tier endorser, their endorsers, and rank(depth) of each of those endorsers.
RETURN target.name, NODES(p)[-2] as endorser, COLLECT(person.name), SIZE(RELATIONSHIPS(p)) as depth 
ORDER BY depth

// one line copy for copy-paste into console
MATCH (target:User{name:"Ben"}), (person:User), p=((person)-[:TRUSTS*..5]->(target)) WHERE ALL(n in NODES(p)[1..-1] WHERE n<>target) RETURN target.name, NODES(p)[-2] as endorser, COLLECT(person.name), SIZE(RELATIONSHIPS(p)) as depth ORDER BY depth

备用返回格式

WITH NODES(p)[-2] as endorser, {people:COLLECT(person.name), depth:SIZE(RELATIONSHIPS(p))} as auth 
RETURN endorser, COLLECT(auth)

// one line copy for copy-paste into console
MATCH (target:User{name:"Ben"}), (person:User), p=((person)-[:TRUSTS*..5]->(target)) WHERE ALL(n in NODES(p)[1..-1] WHERE n<>target) WITH NODES(p)[-2] as endorser, {people:COLLECT(person.name), depth:SIZE(RELATIONSHIPS(p))} as auth RETURN endorser, COLLECT(auth)

更新:替代返回格式以匹配OP的返回表

MATCH (target:User{name:"Rus"}), (person:User), p=((person)-[:TRUSTS*]->(target)) WHERE ALL(n in NODES(p)[1..-1] WHERE n<>target) WITH NODES(p) as n, SIZE(RELATIONSHIPS(p)) as depth RETURN DISTINCT n[-depth] as parent, n[-depth-1] as child, depth ORDER BY depth