1

I am trying to detect cycles in a graph created on postgreSQl and Apache AGE.

The schema for the graph is as follows:



CREATE TABLE modules (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    version VARCHAR(255) NOT NULL
);

CREATE TABLE dependencies (
    module_id INTEGER REFERENCES modules(id),
    dependency_id INTEGER REFERENCES modules(id),
    PRIMARY KEY (module_id, dependency_id)
);

and the sample data is given by

-- Modules
INSERT INTO modules (name, version) VALUES
('Module A', '1.0.0'),
('Module B', '1.1.0'),
('Module C', '1.2.0'),
('Module D', '2.0.0'),
('Module E', '2.1.0');

-- Dependencies
INSERT INTO dependencies (module_id, dependency_id) VALUES
(1, 2),
(1, 3),
(2, 3),
(3, 4),
(4, 5),
(5, 1);

Can someone guide me what the cypher query would be to detect cycles within the graph and also the nodes involved in the cycle.

4 Answers4

1

You can try working out with "WITH RECURSIVE" statement. Here is the official documentation of it.

Other possible way is to proceed with a custom function. Here is how you can create a custom function.

Huzaifa
  • 484
  • 4
  • 8
0

You can try to experiment with the following query to detect cycles per your defined schema:

WITH RECURSIVE detect_cycles(module_id, path, cycle) AS (
SELECT module_id, ARRAY[module_id], false
FROM dependencies
UNION
SELECT d.module_id, path || d.module_id, d.module_id = ANY(path)
FROM dependencies d, detect_cycles c
WHERE d.dependency_id = c.module_id AND NOT cycle
)
SELECT * FROM detect_cycles WHERE cycle;
han
  • 74
  • 7
0

what the cypher query would be to detect cycles within the graph?

I've created a graph only with the cypher syntax. The commands I used to create the graph are:

SELECT * FROM cypher('test', $$
CREATE (:Person {name: 'A'})-[:RELATED_TO]->(:Person {name: 'B'})-[:RELATED_TO]->(:Person {name: 'C'})
$$) AS (a agtype);
 a 
---
(0 rows)

SELECT * FROM cypher('test', $$
  MATCH (a:Person {name: 'A'}), (c:Person {name: 'C'})
  CREATE (c)-[:RELATED_TO]->(a)
$$) AS (a agtype);
 a 
---
(0 rows)

Then, to see if there is a cycle in the graph:

SELECT * FROM cypher('test', $$
  MATCH path=(startNode)-[*]->(startNode)
  RETURN relationships(path)
$$) AS (paths agtype);

So, I believe you would need to somehow execute the same process as the VLE does for your custom tables.

Therefore, as @Huzaifa mentioned, using a RECURSIVE WITH. Something like this would probably work:

WITH RECURSIVE cycle_detection(module_id, dependency_id, path) AS (
  SELECT d.module_id, d.dependency_id, ARRAY[d.module_id, d.dependency_id]
  FROM dependencies d
  UNION ALL
  SELECT d.module_id, d.dependency_id, path || d.dependency_id
  FROM dependencies d
  JOIN cycle_detection c ON c.dependency_id = d.module_id
  WHERE NOT d.dependency_id = ALL(path)
)
SELECT path
FROM cycle_detection
WHERE module_id = ANY(path)
LIMIT 1;
Matheus Farias
  • 716
  • 1
  • 10
-1

The code for that would be something like:

g.V().as('start').
    repeat(out().as('next').
           where('next', neq('start')).
           store('path').by(id)).
    until(out().filter('it', eq('start'))).
    select('path').unfold().dedup().groupCount().unfold().
    filter(select(values).is(gt(1))).
    select(keys).unfold().as('cycle').
    select('cycle', out().where(eq('cycle')).dedup().count().as('cycleSize')).
    filter('cycleSize', gt(1)).
    select('cycle').fold()
tokamak32
  • 27
  • 7