如何在 neo4j 中聚合列表中的元素
How to aggregate across elements in list in neo4j
我是 neo4j 和密码查询的完全初学者。我有一个场景,其中两个 Person 节点 James
和 Karen
在它们之间有 3 个节点。所有节点之间的关系有一个属性,叫做weight
:
CREATE
(j:Person { name: "James" }),
(m:Person { name: "Mary" }),
(d:Person { name: "David" }),
(e:Person { name: "Emily" }),
(t:Person { name: "Todd" }),
(x:Person { name: "Xavier" }),
(k:Person { name: "Karen" }),
(j)-[:KNOWS{weight: 32}]->(m),
(j)-[:KNOWS{weight: 10}]->(d),
(j)-[:KNOWS{weight: 50}]->(e),
(j)-[:KNOWS{weight: 86}]->(t),
(j)-[:KNOWS{weight: 86}]->(x),
(d)-[:KNOWS{weight: 12}]->(e),
(k)-[:KNOWS{weight: 76}]->(e),
(k)-[:KNOWS{weight: 8}]->(t),
(k)-[:KNOWS{weight: 2}]->(x)
我想对这些认识 James
和 Karen
的人进行排名,使用 属性 关系的计算分数,定义为 (x - min(x)/max(x) - min(x)
,一些规范化形式,即
MATCH (:Person{name:'James'})-[:KNOWS]->(:Person)<-[r1:KNOWS]-(:Person{name: 'Karen'})
WITH collect(r1.weight) as a
WITH apoc.coll.min(a) as min_val, apoc.coll.max(a) as max_val
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
WITH p, r2, (r2.weight - min_val)/(max_val - min_val) as score
RETURN p, r2, score
ORDER BY score DESC
╒═════════════════╤═════════════╤═══════╕
│"p" │"r2" │"score"│
╞═════════════════╪═════════════╪═══════╡
│{"name":"Emily"} │{"weight":76}│1 │
├─────────────────┼─────────────┼───────┤
│{"name":"Xavier"}│{"weight":2} │0 │
├─────────────────┼─────────────┼───────┤
│{"name":"Todd"} │{"weight":8} │0 │
└─────────────────┴─────────────┴───────┘
有没有更好的方法来做到这一点而不必重复寻找匹配节点的过程,即
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
更新
这是另一种尝试
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r:KNOWS]-(:Person{name: 'Karen'})
WITH r, apoc.map.fromLists(["name", "r_weight"],[p.name, r.weight]) as person
WITH collect(person) as people, collect(r.weight) as w
WITH people, apoc.coll.min(w) as min_val, apoc.coll.max(w) as max_val
UNWIND people as pp
WITH pp, (pp.r_weight - min_val)/(max_val - min_val) as score
RETURN pp, score
ORDER BY score DESC
╒══════════════════════════════╤═══════╕
│"pp" │"score"│
╞══════════════════════════════╪═══════╡
│{"name":"Emily","r_weight":76}│1 │
├──────────────────────────────┼───────┤
│{"name":"Xavier","r_weight":2}│0 │
├──────────────────────────────┼───────┤
│{"name":"Todd","r_weight":8} │0 │
└──────────────────────────────┴───────┘
有没有比我粗暴的方法更干净的方法?
我通常UNWIND
上一个RANGE
来处理并行列表。我就是这样做的。
MATCH (:Person{name:'James'})-[r1:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
WITH p, r1.weight + r2.weight AS weight
WITH COLLECT(p) AS people,
COLLECT(weight) as weights,
max(weight) AS maxWeight,
min(weight) AS minWeight
UNWIND RANGE(0, SIZE(people)-1) AS idx
RETURN people[idx].name as person,
weights[idx] AS weight,
toFloat(weights[idx] - minWeight)/(maxWeight - minWeight) AS score
ORDER BY score desc
我是 neo4j 和密码查询的完全初学者。我有一个场景,其中两个 Person 节点 James
和 Karen
在它们之间有 3 个节点。所有节点之间的关系有一个属性,叫做weight
:
CREATE
(j:Person { name: "James" }),
(m:Person { name: "Mary" }),
(d:Person { name: "David" }),
(e:Person { name: "Emily" }),
(t:Person { name: "Todd" }),
(x:Person { name: "Xavier" }),
(k:Person { name: "Karen" }),
(j)-[:KNOWS{weight: 32}]->(m),
(j)-[:KNOWS{weight: 10}]->(d),
(j)-[:KNOWS{weight: 50}]->(e),
(j)-[:KNOWS{weight: 86}]->(t),
(j)-[:KNOWS{weight: 86}]->(x),
(d)-[:KNOWS{weight: 12}]->(e),
(k)-[:KNOWS{weight: 76}]->(e),
(k)-[:KNOWS{weight: 8}]->(t),
(k)-[:KNOWS{weight: 2}]->(x)
我想对这些认识 James
和 Karen
的人进行排名,使用 属性 关系的计算分数,定义为 (x - min(x)/max(x) - min(x)
,一些规范化形式,即
MATCH (:Person{name:'James'})-[:KNOWS]->(:Person)<-[r1:KNOWS]-(:Person{name: 'Karen'})
WITH collect(r1.weight) as a
WITH apoc.coll.min(a) as min_val, apoc.coll.max(a) as max_val
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
WITH p, r2, (r2.weight - min_val)/(max_val - min_val) as score
RETURN p, r2, score
ORDER BY score DESC
╒═════════════════╤═════════════╤═══════╕
│"p" │"r2" │"score"│
╞═════════════════╪═════════════╪═══════╡
│{"name":"Emily"} │{"weight":76}│1 │
├─────────────────┼─────────────┼───────┤
│{"name":"Xavier"}│{"weight":2} │0 │
├─────────────────┼─────────────┼───────┤
│{"name":"Todd"} │{"weight":8} │0 │
└─────────────────┴─────────────┴───────┘
有没有更好的方法来做到这一点而不必重复寻找匹配节点的过程,即
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
更新 这是另一种尝试
MATCH (:Person{name:'James'})-[:KNOWS]->(p:Person)<-[r:KNOWS]-(:Person{name: 'Karen'})
WITH r, apoc.map.fromLists(["name", "r_weight"],[p.name, r.weight]) as person
WITH collect(person) as people, collect(r.weight) as w
WITH people, apoc.coll.min(w) as min_val, apoc.coll.max(w) as max_val
UNWIND people as pp
WITH pp, (pp.r_weight - min_val)/(max_val - min_val) as score
RETURN pp, score
ORDER BY score DESC
╒══════════════════════════════╤═══════╕
│"pp" │"score"│
╞══════════════════════════════╪═══════╡
│{"name":"Emily","r_weight":76}│1 │
├──────────────────────────────┼───────┤
│{"name":"Xavier","r_weight":2}│0 │
├──────────────────────────────┼───────┤
│{"name":"Todd","r_weight":8} │0 │
└──────────────────────────────┴───────┘
有没有比我粗暴的方法更干净的方法?
我通常UNWIND
上一个RANGE
来处理并行列表。我就是这样做的。
MATCH (:Person{name:'James'})-[r1:KNOWS]->(p:Person)<-[r2:KNOWS]-(:Person{name: 'Karen'})
WITH p, r1.weight + r2.weight AS weight
WITH COLLECT(p) AS people,
COLLECT(weight) as weights,
max(weight) AS maxWeight,
min(weight) AS minWeight
UNWIND RANGE(0, SIZE(people)-1) AS idx
RETURN people[idx].name as person,
weights[idx] AS weight,
toFloat(weights[idx] - minWeight)/(maxWeight - minWeight) AS score
ORDER BY score desc