All Products
Search
Document Center

AnalyticDB:Create and use a graph analysis engine

Last Updated:Dec 26, 2025

This topic describes how to create and use a graph analysis engine in AnalyticDB for PostgreSQL.

What is Cypher?

Cypher is an open source declarative query language provided by the openCypher project. It is similar to SQL but is optimized for graph data structures. With intuitive and natural language-like syntax, Cypher can clearly express relationships between nodes and define graph-matching patterns, allowing efficient and easy graph data queries. Example:

MATCH (n:nodes)-[r:ARE_CONNECTED_TO]->(o:otherNodes)
RETURN n,r,o

The preceding Cypher query uses pattern matching to find all nodes and relationships in a graph that satisfy specific conditions. In the query, (n:nodes) represents a node with the nodes label, and n is its alias. [r:ARE_CONNECTED_TO] represents a relationship with the ARE_CONNECTED_TO label, and r is its alias. (o:otherNodes) represents a target node with the otherNodes label, and o is its alias. The query returns all source nodes, target nodes, and the relationships between them that match this pattern.

Syntax

Node syntax

In Cypher, you can use a pair of parentheses () to represent a node. The following items describe common node representations and their meanings:

  • (): An anonymous node. This represents an anonymous node without a specified label. It is typically used to match any node.

  • (node): A node with a variable. This assigns a variable name, such as node, to a node so you can reference it in queries.

  • (:City): A node with a label. This represents a node that has the City label. Labels are similar to table names or classification identifiers in a relational database. You can use them to filter for specific types of nodes.

  • (city:City): A node with a variable and a label. This assigns the variable city and the label City to a node. This makes the node easy to reference and clearly defines its type.

  • (city:City {name: 'Hangzhou'}): A node with properties. This adds the property {name: 'Hangzhou'} to the node to further define its characteristics. This is similar to a WHERE clause in a relational database. It allows for an exact match of nodes that have specific property values.

  • (city:City {name: 'Hangzhou', province: 'Zhejiang'}): A node with multiple properties. A node can contain multiple properties to support more complex filtering conditions.

Relationship syntax

In Cypher, you can use a pair of hyphens -- to represent a relationship. For a directed relationship, you can add an arrow to one end, such as -->. To describe a relationship in more detail, you can use square brackets []. The brackets can contain information such as variables, types, and properties. The following items describe common relationship representations and their meanings:

  • --: An anonymous, undirected relationship without a specified type.

  • -->: An anonymous, directed relationship without a specified type.

  • -[role]->: Defines a variable role for the relationship so you can reference it in queries.

  • -[:ACTED_IN]->: Specifies the relationship type as ACTED_IN. This is similar to a label for a node.

  • -[role:ACTED_IN]->: Defines both the variable role and the type ACTED_IN for the relationship.

  • -[role:ACTED_IN {roles: ['Neo']}]->: Adds the property {roles: ['Neo']} to the relationship to describe its specific characteristics.

The syntax and semantics for relationships are very similar to those for nodes.

  • Variables: A variable in a relationship, such as role, is similar to a variable in a node. You can use it for reference in queries.

  • Types: A type for a relationship, such as ACTED_IN, is similar to a label for a node. You can use it to categorize and filter for specific relationships.

  • Properties: Properties of a relationship, such as {roles: ['Neo']}, are equivalent to the properties of a node. They support the key-value format to describe the relationship in detail.

Pattern syntax

Node and relationship syntax can be integrated to build patterns that convey rich semantic information. Sample pattern expression:

(city_from:City {province: 'Zhejiang'})-[:NEXT_TO]-(city_next:City {province: 'Jiangsu'})

Expression meanings:

  • (city_from:City {province: 'Zhejiang'}): Represents a node with the City label and a province property of 'Zhejiang'. This is a city in Zhejiang province.

  • (city_next:City {province: 'Jiangsu'}): Represents another node with the City label and a province property of 'Jiangsu'. This is a city in Jiangsu province.

  • -[:NEXT_TO]-: Represents an undirected edge of the type NEXT_TO. It describes the geographical adjacency of the two cities.

This pattern expression matches the relationship between adjacent cities in Zhejiang and Jiangsu provinces.

  • city_from and city_next represent the city nodes in Zhejiang and Jiangsu provinces, respectively.

  • [:NEXT_TO] represents the geographical adjacency between the two cities.

Version limitations

AnalyticDB for PostgreSQL V7.0 instances of V7.2.1.0 or later.

Note

You can view the minor version on the Basic Information page of an instance in the AnalyticDB for PostgreSQL console. If your instance does not meet the required versions, update the minor version of the instance.

Prerequisites

  • The age extension is installed for an AnalyticDB for PostgreSQL instance.

    The age extension is automatically installed on AnalyticDB for PostgreSQL V7.0 instances that have a minor engine version of 7.2.1.4 or later.

  • The ag_catalog schema is added to the search path specified by the search_path parameter to simplify queries. You can use one of the following methods:

    • Session-level configuration.

      SET search_path TO "$user", public, ag_catalog;
    • Database-level permanent configuration.

      ALTER DATABASE <database_name> SET search_path TO "$user", public, ag_catalog;
  • (Optional) The initial account or a privileged account that has the RDS_SUPERUSER permission is used to grant other users access to the ag_catalog schema.

    GRANT USAGE ON SCHEMA ag_catalog TO <username>;

Create and use a graph analysis engine

Create a graph

Syntax

You can use the create_graph function to create a graph.

SELECT create_graph('<graph_name>');

Parameters

graph_name: The name of the graph.

Example

SELECT create_graph('relation');

Write data

Syntax

Call the cypher function in ag_catalog with an expression to create nodes and relationships.

SELECT * FROM cypher('<graph_name>', $$
  /* Write a Cypher expression.*/
  $$) AS (result_a agtype, result_b agtype);

Example

The following graph contains three person nodes (Zhang San, Li Si, and Wang Wu) and two company nodes (Company A and Company C). Persons are connected to companies using the EMPLOYED edges, and persons are connected to each other using the FRIENDS and TEACHER edges.

image

Write data to the relation graph.

SELECT * FROM cypher('relation', $$
  CREATE (ZhangSan:Person {name: 'Zhang San'})
  CREATE (LiSi:Person {name: 'Li Si'})
  CREATE (WangWu:Person {name: 'Wang Wu'})
  CREATE (company_a:Company {name: 'Company A'})
  CREATE (company_c:Company {name: 'Company C'})
  CREATE (ZhangSan)-[:EMPLOYED]->(company_a)
  CREATE (LiSi)-[:EMPLOYED]->(company_c)
  CREATE (WangWu)-[:EMPLOYED]->(company_a)
  CREATE (ZhangSan)-[:FRIENDS]->(LiSi)
  CREATE (WangWu)-[:TEACHER]->(ZhangSan)
$$) AS (result_a agtype)

Query data

Syntax

You can use the MATCH and RETURN statements to query data. MATCH defines the graph pattern to match, which specifies the nodes, relationships, and their properties to find. RETURN specifies the content to return in the query result.

SELECT * FROM cypher('<graph_name>', $$
  MATCH <patterns>
  WHERE <expression> --optional
  RETURN <variables>
$$) AS (result_a agtype);

Query all data

  • Find all nodes that have the Person label.

    SELECT * FROM cypher('relation', $$
      MATCH (m:Person)
      RETURN m
    $$) AS (result_a agtype)

    The following is the result:

                                            result_a                                         
    -----------------------------------------------------------------------------------------
     {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::vertex
     {"id": 844424930131970, "label": "Person", "properties": {"name": "Li Si"}}::vertex
     {"id": 844424930131971, "label": "Person", "properties": {"name": "Wang Wu"}}::vertex
    (3 rows)
  • Find all edges that have the EMPLOYED label.

    SELECT * FROM cypher('relation', $$
      MATCH (:Person)-[r:EMPLOYED]->(:Company)
      RETURN r
    $$) AS (result_a agtype);

    The following result is returned:

                                                                result_a                                                            
    --------------------------------------------------------------------------------------------------------------------------------
     {"id": 1407374883553281, "label": "EMPLOYED", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge
     {"id": 1407374883553282, "label": "EMPLOYED", "end_id": 1125899906842626, "start_id": 844424930131970, "properties": {}}::edge
     {"id": 1407374883553283, "label": "EMPLOYED", "end_id": 1125899906842625, "start_id": 844424930131971, "properties": {}}::edge
    (3 rows)

Query partial data (filtered data)

When you perform pattern matching in a graph and need to return specific data, you can use the WHERE clause to filter the matched results based on conditions.

  • Query all employees of Company A.

    SELECT * FROM cypher('relation', $$
      MATCH (p:Person)-[:EMPLOYED]->(a:Company)
      WHERE a.name='Company A'
      RETURN p
    $$) AS (result_a agtype);

    The following shows the result.

                                            result_a                                         
    -----------------------------------------------------------------------------------------
     {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::vertex
     {"id": 844424930131971, "label": "Person", "properties": {"name": "Wang Wu"}}::vertex
    (2 rows)
  • Query Wang Wu's students.

    SELECT * FROM cypher('relation', $$
      MATCH (p1:Person)-[:TEACHER]->(p2:Person)
      WHERE p1.name='Wang Wu'
      RETURN p2
    $$) AS (result_a agtype)

    The result is:

                                            result_a                                         
    -----------------------------------------------------------------------------------------
     {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::vertex
    (1 row)

Update data (nodes or edges)

For existing data in a graph, including nodes and relationships, you can modify the data by matching the target object and using the SET keyword to add or update properties.

Syntax

SELECT * FROM cypher('<graph_name>', $$
  MATCH <patterns>
  SET <property>
  RETURN <variable>
$$) AS (result_a agtype)

Examples

  • Change Zhang San's name to Zhang 3.

    SELECT * FROM cypher('relation', $$
      MATCH (p:Person {name:'Zhang San'})
      SET p.name='Zhang 3'
      RETURN p
    $$) AS (result_a agtype);

    The results of the update are as follows:

                                           result_a                                        
    ---------------------------------------------------------------------------------------
     {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang 3"}}::vertex
    (1 row)
  • Add a gender label with the value male to Zhang San.

    SELECT * FROM cypher('relation', $$
      MATCH (p:Person {name: 'Zhang 3'})
      SET p.gender = 'male'
      RETURN p
    $$) AS (result_a agtype);

    The results of the update are as follows:

                                                    result_a                                                 
    ---------------------------------------------------------------------------------------------------------
     {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang 3", "gender": "male"}}::vertex
    (1 row)

Delete data

Remove labels

When a label on a node or an edge is no longer needed, you can use the REMOVE keyword to delete it.

Syntax

SELECT * FROM cypher('<graph_name>', $$
  MATCH <patterns>
  REMOVE <property>
$$) AS (result_a agtype);

Example

Remove the gender label from Zhang San.

SELECT * FROM cypher('relation', $$
  MATCH (p:Person {name: 'Zhang 3'})
  REMOVE p.gender
  RETURN p
$$) AS (result_a agtype);

Delete nodes

You can use the DELETE keyword to delete nodes or edges.

Syntax

SELECT * FROM cypher('<graph_name>', $$
  MATCH <patterns>
  DELETE <variable>
$$) AS (result_a agtype);

Example

Create a node named Zhao Liu, and then delete the node.

-- Create a node named Zhao Liu.
SELECT * FROM cypher('relation', $$
  CREATE (:Person {name: 'Zhao Liu'})
$$) AS (result_a agtype)

-- Delete the node.
SELECT * FROM cypher('relation', $$
  MATCH(p:Person {name: 'Zhao Liu'})
  DELETE p
$$) AS (result_a agtype)
Note

You cannot directly delete a node that has edges. Instead, use the DETACH DELETE statement to delete the node and its edges.

Delete edges

First, add a node named 'Zhao Liu' and an edge to specify that Zhao Liu is employed by Company C. Then, delete the employment relationship. To delete the relationship, you can specify the person's name and the company's name in the WHERE clause.

-- Create a node named Zhao Liu and an EMPLOYED edge between Zhao Liu and Company C.
SELECT * FROM cypher('relation', $$
  CREATE (ZhaoLiu:Person {name: 'Zhao Liu'})
  CREATE (ZhaoLiu)-[:EMPLOYED]->(:Company {name: 'Company C'})
$$) AS (result_a agtype);

-- Delete the edge.
SELECT * FROM cypher('relation', $$
  MATCH (p:Person)-[r:EMPLOYED]->(c:Company)
  WHERE p.name='Zhao Liu' AND c.name='Company C'
  DELETE r
$$) AS (result_a agtype);

Delete nodes and their edges

If a node has associated edges, you cannot directly delete the node. You must use the DETACH DELETE statement to delete both the node and its edges.

Syntax

SELECT * FROM cypher('<graph_name>', $$
  MATCH <patterns>
  DETACH DELETE <variable>
$$) AS (result_a agtype);

Example

Create a node named Zhao Liu and an EMPLOYED edge between Zhao Liu and Company C. Then, delete the edge and the Zhao Liu node.

-- Create a node named Zhao Liu and an EMPLOYED edge between Zhao Liu and Company C.
SELECT * FROM cypher('relation', $$
  CREATE (ZhaoLiu:Person {name: 'Zhao Liu'})
  CREATE (ZhaoLiu)-[:EMPLOYED]->(:Company {name: 'Company C'})
$$) AS (result_a agtype);

-- Delete the node and its edges.
SELECT * FROM cypher('relation', $$
  MATCH (p:Person {name: 'Zhao Liu'})
  DETACH DELETE p
$$) AS (result_a agtype);