Memgraph Cypher 递归树查询,包括深度和筛选条件。

huangapple go评论59阅读模式
英文:

Memgraph cypher recursive tree with depth and filtering query

问题

I'm using Memgraph (but open to using Neo4j) and need some help on building a recursive query to build out a tree. I'm new to Cypher so my attempts so far haven't been successful. I've played around with the CALL subqueries but can't seem to get the format and ordering right.

我的目标是:

  1. 能够获取一个节点及其直接的边缘 - 但边缘应限制为按边缘属性值排序的特定数量。例如,获取节点A及其3条边,按属性X排序。
  2. 能够获取一个节点,并根据某个变量指定遍历树的深度。例如,获取节点A,对于其3条边中的每一条(按X排序),使用相同的过滤函数获取这些边的边缘,直到深度限制。如果能够过滤掉父节点,使其成为有向树,那就更好了。

一些具体的示例 - 给定以下图形。请注意,这不是真实数据,我知道"age"属性在节点之间不对称。只是为了提问而创建的。

CREATE (n0:Node {name: "a"}) CREATE (n1:Node {name: "b"}) CREATE (n2:Node {name: "c"}) CREATE (n3:Node {name: "d"}) CREATE (n4:Node {name: "e"}) CREATE (n5:Node {name: "f"}) CREATE (n6:Node {name: "g"}) CREATE (n7:Node {name: "h"}) CREATE (n8:Node {name: "i"}) CREATE (n9:Node {name: "j"});
CREATE (n0)-[:KNOWN_FOR {age: 20} ]->(n2) CREATE (n0)-[:KNOWN_FOR {age: 7} ]->(n1) CREATE (n0)-[:KNOWN_FOR {age: 15} ]->(n4) CREATE (n0)-[:KNOWN_FOR {age: 23} ]->(n3) CREATE (n0)-[:KNOWN_FOR {age: 5} ]->(n7) CREATE (n1)-[:KNOWN_FOR {age: 10} ]->(n6) CREATE (n1)-[:KNOWN_FOR {age: 14} ]->(n2) CREATE (n1)-[:KNOWN_FOR {age: 24} ]->(n3) CREATE (n1)-[:KNOWN_FOR {age: 19} ]->(n5) CREATE (n2)-[:KNOWN_FOR {age: 24} ]->(n8) CREATE (n2)-[:KNOWN_FOR {age: 25} ]->(n3) CREATE (n2)-[:KNOWN_FOR {age: 17} ]->(n1) CREATE (n3)-[:KNOWN_FOR {age: 7} ]->(n4) CREATE (n3)-[:KNOWN_FOR {age: 10} ]->(n7) CREATE (n3)-[:KNOWN_FOR {age: 25} ]->(n6) CREATE (n3)-[:KNOWN_FOR {age: 22} ]->(n1)
CREATE (n4)-[:KNOWN_FOR {age: 21} ]->(n0) CREATE (n4)-[:KNOWN_FOR {age: 24} ]->(n6) CREATE (n4)-[:KNOWN_FOR {age: 17} ]->(n8) CREATE (n5)-[:KNOWN_FOR {age: 14} ]->(n9) CREATE (n5)-[:KNOWN_FOR {age: 8} ]->(n0) CREATE (n5)-[:KNOWN_FOR {age: 15} ]->(n8) CREATE (n5)-[:KNOWN_FOR {age: 18} ]->(n6) CREATE (n5)-[:KNOWN_FOR {age: 22} ]->(n4) CREATE (n6)-[:KNOWN_FOR {age: 7} ]->(n4) CREATE (n6)-[:KNOWN_FOR {age: 21} ]->(n2) CREATE (n7)-[:KNOWN_FOR {age: 25} ]->(n3) CREATE (n8)-[:KNOWN_FOR {age: 18} ]->(n7) CREATE (n8)-[:KNOWN_FOR {age: 12} ]->(n3) CREATE (n9)-[:KNOWN_FOR {age: 14} ]->(n4) CREATE (n9)-[:KNOWN_FOR {age: 15} ]->(n3) CREATE (n9)-[:KNOWN_FOR {age: 7} ]->(n2) CREATE (n9)-[:KNOWN_FOR {age: 14} ]->(n8);

示例:

获取节点A及其3个按KNOWN_FOR age降序排序的子节点,其中age > 5。应返回:

A ->
  - D (age: 23)
  - C (age: 20)
  - E (age: 15)

获取节点A,并将其子节点深度限制为3,其中其子节点限制为2,按age降序排序。应返回:

A 
  -> D (age: 23)
    -> G (age: 25)
      -> C (age: 21)
      -> E (age: 7)
    -> B (age: 22)
      -> D (age: 24)
      -> F (age: 19)
  -> C (age: 20)
    -> D (age: 25)
      -> G (age: 25)
      -> B (age: 22)
    -> I (age: 24)
      -> H (age: 18)
      -> D (age: 12)
  -> E (age: 15)
    -> G (age: 24)
      -> C (age: 21)
      -> E (age: 7)
    -> A (age: 21)
      -> D (age: 23)
      -> C (age: 20)

我不太在意返回数据的格式,只要包括节点和它们之间的关系值。像这样的简单格式是理想的:

A, D, 23
D, G, 25

但如果是嵌套数组,我可以在封装查询的函数中解析它。

英文:

I'm using Memgraph (but open to using Neo4j) and need some help on building a recursive query to build out a tree. I'm new to Cypher so my attempts so far haven't been successful. I've played around with the CALL subqueries but can't seem to get the format and ordering right.

My goals are:

  1. Be able to fetch a Node, and its direct edges - but the edges should be limited to a certain number sorted by a edge property value. E.g. Get Node A and 3 of its edges ordered by property X.
  2. Be able to fetch a Node, and based on some variable be able to specify the depth to "walk" to tree. E.g. Get Node A, and for each of its 3 edges (sorted by X), get those edge's edges the using the same filter function, up to the depth limit. Bonus points if it can filter out the parent node so it's only a directed tree.

Some concrete examples - given the following graph. Note this is not real data and I'm aware the "age" property is not symmetrical between Nodes. Just threw it together for the question.

CREATE (n0:Node {name: "a"}) CREATE (n1:Node {name: "b"}) CREATE (n2:Node {name: "c"}) CREATE (n3:Node {name: "d"}) CREATE (n4:Node {name: "e"}) CREATE (n5:Node {name: "f"}) CREATE (n6:Node {name: "g"}) CREATE (n7:Node {name: "h"}) CREATE (n8:Node {name: "i"}) CREATE (n9:Node {name: "j"});
CREATE (n0)-[:KNOWN_FOR {age: 20} ]->(n2) CREATE (n0)-[:KNOWN_FOR {age: 7} ]->(n1) CREATE (n0)-[:KNOWN_FOR {age: 15} ]->(n4) CREATE (n0)-[:KNOWN_FOR {age: 23} ]->(n3) CREATE (n0)-[:KNOWN_FOR {age: 5} ]->(n7) CREATE (n1)-[:KNOWN_FOR {age: 10} ]->(n6) CREATE (n1)-[:KNOWN_FOR {age: 14} ]->(n2) CREATE (n1)-[:KNOWN_FOR {age: 24} ]->(n3) CREATE (n1)-[:KNOWN_FOR {age: 19} ]->(n5) CREATE (n2)-[:KNOWN_FOR {age: 24} ]->(n8) CREATE (n2)-[:KNOWN_FOR {age: 25} ]->(n3) CREATE (n2)-[:KNOWN_FOR {age: 17} ]->(n1) CREATE (n3)-[:KNOWN_FOR {age: 7} ]->(n4) CREATE (n3)-[:KNOWN_FOR {age: 10} ]->(n7) CREATE (n3)-[:KNOWN_FOR {age: 25} ]->(n6) CREATE (n3)-[:KNOWN_FOR {age: 22} ]->(n1)CREATE (n4)-[:KNOWN_FOR {age: 21} ]->(n0) CREATE (n4)-[:KNOWN_FOR {age: 24} ]->(n6) CREATE (n4)-[:KNOWN_FOR {age: 17} ]->(n8) CREATE (n5)-[:KNOWN_FOR {age: 14} ]->(n9) CREATE (n5)-[:KNOWN_FOR {age: 8} ]->(n0) CREATE (n5)-[:KNOWN_FOR {age: 15} ]->(n8) CREATE (n5)-[:KNOWN_FOR {age: 18} ]->(n6) CREATE (n5)-[:KNOWN_FOR {age: 22} ]->(n4) CREATE (n6)-[:KNOWN_FOR {age: 7} ]->(n4) CREATE (n6)-[:KNOWN_FOR {age: 21} ]->(n2) CREATE (n7)-[:KNOWN_FOR {age: 25} ]->(n3) CREATE (n8)-[:KNOWN_FOR {age: 18} ]->(n7) CREATE (n8)-[:KNOWN_FOR {age: 12} ]->(n3) CREATE (n9)-[:KNOWN_FOR {age: 14} ]->(n4) CREATE (n9)-[:KNOWN_FOR {age: 15} ]->(n3) CREATE (n9)-[:KNOWN_FOR {age: 7} ]->(n2) CREATE (n9)-[:KNOWN_FOR {age: 14} ]->(n8);

Memgraph Cypher 递归树查询,包括深度和筛选条件。

Examples

Get Node A and 3 of its children ordered by KNOWN_FOR age desc, where age > 5. Should return:

A ->
  - D (age: 23)
  - C (age: 20)
  - E (age: 15)

Get Node A, and its children to a depth of 3, where its children have a limit of 2 order by age desc. Should return:

A 
  -> D (age: 23)
    -> G (age: 25)
      -> C (age: 21)
      -> E (age: 7)
    -> B (age: 22)
      -> D (age: 24)
      -> F (age: 19)
  -> C (age: 20)
    -> D (age: 25)
      -> G (age: 25)
      -> B (age: 22)
    -> I (age: 24)
      -> H (age: 18)
      -> D (age: 12)
  -> E (age: 15)
    -> G (age: 24)
      -> C (age: 21)
      -> E (age: 7)
    -> A (age: 21)
      -> D (age: 23)
      -> C (age: 20)

I don't mind to much on the format of the return data, as long as it includes the nodes and relationship value between them. Something as simple as this is ideal:

A, D, 23
D, G, 25

But if its a nested array, I can parse it out on the function that wraps the query.

答案1

得分: 1

根据我理解,你正在寻找bfs遍历。在Memgraph上,你可以在这里查看:https://memgraph.com/docs/memgraph/reference-guide/built-in-graph-algorithms#breadth-first-search

对于第一个问题("获取节点 A 及其 3 个子节点,按照 KNOWN_FOR 的年龄降序排列,其中年龄大于 5。"),这应该是一个查询:

MATCH path=(n:Node {name:"a"})-[rels *bfs..1]->(m)
WITH n, m, rels[0] as rel0
WHERE rel0.age > 5
RETURN n.name, m.name, rel0.age
ORDER BY rel0.age DESC;

基本上,在这里,你获取了一个具有属性名为"a"的节点,然后进行了最多 1 步的bfs到某个节点m。现在,在变量rels中,你将拥有所有bfs访问的关系。在bfs中,它将以某种顺序访问关系,但要在输出上获取排序的数据,你将需要使用ORDER BY,然后引用rel0的属性age
另外,我在这里得到了不同的输出,我认为你遗漏了值为 7 的节点 "B"。

对于第二个问题,如果我理解正确,你想从节点 A 扩展到 3 步,然后按照age属性排序,首先比较第一次扩展上的所有关系,然后再比较第二次扩展上的关系。

在我看来,Memgraph 有两种选项:

MATCH path=(n:Node {name:"a"})-[rels *bfs..3]->(m)
WITH path, n, m, rels[0] as rel0, rels[1] as rel1, rels[2] as rel2
RETURN n.name ,m.name, rel0.age, rel1.age, rel2.age, extract(p IN nodes(path) | p.name) as nodes
ORDER BY rel0.age DESC, rel1.age DESC, rel2.age DESC;

和第二个选项:

MATCH path=(n:Node {name:"a"})-[rels *bfs..3]->(m)
WITH n, m, extract(r IN rels | r.age) as ages_list, rels
WHERE ages_list[0] > 5
RETURN n.name ,m.name, ages_list
ORDER BY ages_list[0] DESC, ages_list[1] DESC;

第二个选项背后的思想是在列表中提取属性,然后比较列表的值。如果列表中没有值,不会抛出错误,它会返回空值。基本上,它将首先比较第一次扩展上的所有年龄值,然后在第二次扩展上进行比较,依此类推...

如果你有任何更多的问题,请告诉我。此外,关于 BFS 的一个很好的教程可以在 Memgraph 的 Playground 中找到:https://playground.memgraph.com/topic/cypher-breadth-first-search。

要了解更多文档,请查看我提供的 Memgraph 网站链接,这将会很有帮助。

英文:

from what I understood that you are looking for bfs traversal. On Memgraph you can check it out here: https://memgraph.com/docs/memgraph/reference-guide/built-in-graph-algorithms#breadth-first-search

For the first question ("Get Node A and 3 of its children ordered by KNOWN_FOR age desc, where age > 5."), this should be a query:

MATCH path=(n:Node {name:"a"})-[rels *bfs..1]->(m)
WITH n, m,  rels[0] as rel0
WHERE rel0.age > 5
RETURN n.name, m.name, rel0.age
ORDER BY rel0.age DESC;

Basically, here, you get a node with property name "a", then do bfs of up to max 1 step to some node m. Now, in variable rels you will have all the relationships that bfs visits. In bfs it will visit relationships at some order, but to get data sorted on output you will need ORDER BY and then reference rel0's property age.
Also, I am getting different output here, I think you are missing node "B" with value 7.

For the second question () if I understood correctly you want to expand from node A up to 3 steps and then order by age property in a way that you first compare all relationships on the first expansion, and then on second.

There are two options for that as I see it in Memgraph:

MATCH path=(n:Node {name:"a"})-[rels *bfs..3]->(m)
WITH path, n, m,  rels[0] as rel0, rels[1] as rel1, rels[2] as rel2
RETURN n.name ,m.name, rel0.age, rel1.age, rel2.age, extract(p IN nodes(path) | p.name) as nodes
ORDER BY rel0.age DESC, rel1.age DESC, rel2.age DESC;

and second one:

MATCH path=(n:Node {name:"a"})-[rels *bfs..3]->(m)
WITH n, m,  extract(r IN rels | r.age) as ages_list, rels
WHERE ages_list[0] > 5
RETURN n.name ,m.name, ages_list
ORDER BY ages_list[0] DESC, ages_list[1] DESC;

The idea behind the second option is to extract properties in the list and then compare the values of the list. There is no error thrown if there is no value in the list, it will return null. Basically, it will first compare all age values on first expansion, and then on second, etc...

Let me know if you have any more questions. Also, a good tutorial on BFS can be found on Memgraph's Playground: https://playground.memgraph.com/topic/cypher-breadth-first-search.

For more docs, check Memgraph's site I linked, it should be helpful.

huangapple
  • 本文由 发表于 2023年5月30日 11:56:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361528.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定