图数据库(Graph Database)用于存储图数据,适合处理社交网络、知识图谱等复杂关系。使用图查询语言(如Cypher、Gremlin)进行操作。PolarDB兼容OpenCypher语法,支持创建、查询、更新和删除图数据,包括模式匹配、过滤、MERGE避免重复、可视化工具等功能,简化图数据的管理和应用。
前提条件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本14.12.24.0及以上)。
基本概念
图(Graph):图是由节点和边组成的数据结构。例如,社交网络就是一个典型的图,其中每个人都是一个节点,他们之间的关系(如朋友、家人、同事等)就是边。
节点(Node):节点是图数据库中的基本元素,表示数据库中的实体。节点可以具有属性,用于存储与实体相关的信息。例如,在一个社交网络中,节点可以表示用户、公司、组织等实体。
边(Edge):边是连接节点的关系。边可以具有权重、方向等属性,用于表示关系的强度和方向。例如,在一个社交网络中,边可以表示用户之间的关注、好友、粉丝等关系。
标签(Label):标签是一种用于标识节点或边的分类或属性。标签帮助您语义化数据,以便更容易地进行查询和理解。例如,在社交网络中,节点的分类可以是人(Person),或公司(Company),边的标签可以是认识(Knows)或工作与(WorkIn)等。
属性图:如果节点包含属性(包含有关主题的详细信息)或边包含属性(关系的详细信息),则称为属性图。以下为一个同事关系的属性图,节点和边上都带有相关的属性:
图数据库(Graph Database):是一种特殊的数据库,使用图来存储数据,节点(Node)表示实体,边(Edge)表示关系。非常适合处理复杂的关系数据,如社交网络、信任网络、知识图谱等。
图数据库使用图查询语言(Graph Query Language)查询数据,如Cypher、Gremlin等。PolarDB兼容OpenCypher语法。OpenCypher是Cypher的一个开源子集,其大部分特性可以认为等同于Cypher。
模式
属性
在Cypher语言中,使用一对花括号{}
来表示属性。属性由键值对(Key-Value)组成,类似于常见的JSON结构。键名为一个字符串,属性值可以是字符串、数值,也可以是数组。例如,{name: 'Reeves'}
表示名字叫Reeves
。
节点
在Cypher语言中,使用一对括号()
来表示节点。以下是一些节点表示的示例:
()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: 'The Matrix'})
(matrix:Movie {title: 'The Matrix', released: 1997})
其中:
最简单的形式
()
,表示一个匿名且未表征的节点。若需在其他位置引用该节点,可以添加一个变量,例如:
(matrix)
。变量仅适用于单个语句,在其他语句中则可能具有不同或无意义的含义。:Movie
模式声明节点的标签。这允许我们限制模式,从而防止其匹配其他标签的节点。{title: 'The Matrix'}
声明节点的属性,例如,属性可用于存储信息或限制模式。
边
在Cypher语言中,使用一对短划线--
表示无向边,使用一端带有箭头 <--
、-->
表示有向边。方括号表达式[...]
可用于添加详细信息,包括变量、属性和类型信息。以下是一些边表示的示例:
--
-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ['Neo']}]->
其中:
--
表示一个匿名的无向边。-->
表示一个匿名的有向边。可以定义一个变量(例如,
role
),以便在语句的其他地方使用。关系的标签(例如,
:ACTED_IN
)类似于节点的标签。属性(例如,
roles: ['Neo']
)与节点属性定义方法一致。
示例
以下通过一个简单的示例展示PolarDB中图的基本使用方法。示例数据为一个基础的电影数据库,涵盖了演员及电影的相关信息。
创建插件
请使用高权限账号执行如下语句,创建高权限账号请参考创建数据库账号。
CREATE EXTENSION age;
设置数据库
对于每次连接,都需要将ag_catalog
添加到search_path
以简化查询,并通过get_cypher_keywords
函数实现插件的加载:
SET search_path = ag_catalog, "$user", public;
SELECT * FROM get_cypher_keywords() limit 0;
强烈建议使用高权限账号设置数据库参数,以永久加载插件,从而在每次连接时无需重复执行上述操作,以简化使用流程。
ALTER DATABASE <dbname> SET search_path = "$user", public, ag_catalog;
ALTER DATABASE <dbname> SET session_preload_libraries TO 'age';
允许普通用户使用AGE
在ag_catalog
模式为普通用户授予USAGE
权限。
GRANT USAGE ON SCHEMA ag_catalog TO <username>;
如普通用户只是RW用户,需要额外授予创建表的CREATE权限。
GRANT CREATE ON DATABASE <dbname> TO <username>;
查询结构
PolarDB中的Cypher查询是通过调用ag_catalog
中的一个名为cypher
的函数构建的,该函数返回一个SETOF records。以下是一个典型的查询示例:
SELECT * FROM cypher('graph_name', $$
/* 在此处编写 Cypher 查询 */
$$) AS (result1 agtype, result2 agtype);
其中,graph_name
是图的名称,/* */
内部分可使用实际Cypher查询进行替代。
创建图
在使用图之前,首先需要进行图的创建。创建图使用位于ag_catalog
命名空间中的create_graph
函数。
语法如下:
SELECT create_graph('<graph_name>');
示例:
创建一个名为moviedb
的图。
SELECT create_graph('moviedb');
插入数据
使用以下SQL语句向moviedb
图中插入示例数据:
SELECT * FROM cypher('moviedb', $$
CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)
$$) AS (result1 agtype);
其中,包含了5个节点,其中3个的标签为电影(Movie),2个为人员(Person)。3条边,其中2条边的标签为表演(ACTED_IN),一条边为导演(DIRECTED)。关系图如下所示:
查询数据
数据查询
在Cypher中,使用MATCH
+RETURN
这两个关键字实现数据的查询。其中:
MATCH
实现模式匹配,用于寻找与指定模式相同的内容。RETURN
关键字指定希望从Cypher查询返回的值或结果。
语法如下:
SELECT * FROM cypher('graph_name', $$
MATCH <patterns>
RETURN <variables>
$$) AS (result1 agtype);
示例:
查找包含
Movie
标签的所有节点。SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) RETURN m $$) AS (result1 agtype);
查找标签为
ACTED_IN
的连接Person
和Movie
的边。SELECT * FROM cypher('moviedb', $$ MATCH (:Person)-[r:ACTED_IN]->(:Movie) RETURN r $$) AS (result1 agtype);
数据过滤
当在图中进行模式匹配并仅需返回感兴趣的数据子集时,可以使用WHERE子句。该子句允许通过布尔表达式对数据子集进行过滤。
示例:
查询标题为
The Matrix
的所有电影。SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) WHERE m.title = 'The Matrix' RETURN m $$) AS (result1 agtype);
查询标题为
Forrest Gump
的所有演员。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.title = 'Forrest Gump' RETURN p $$) AS (result1 agtype);
查询发布时间晚于2000年的电影的演员。
SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.released > 2000 RETURN p, m $$) AS (result1 agtype, result2 agtype);
创建节点或边
在Cypher中,可以使用关键字CREATE
创建一个全新的节点或边。
语法如下:
SELECT * FROM cypher('<graph_name>', $$
CREATE <patterns>
$$) AS (result1 agtype);
示例:
创建一个标签为
Person
的节点,其中,属性的名字叫Tom Tykwer
,出生时间为1965
。SELECT * FROM cypher('moviedb', $$ CREATE (:Person {name: 'Tom Tykwer', born: 1965}) $$) AS (result1 agtype);
创建一个Person
Tom Tykwer
和电影Cloud Atlas
的边,表示Tom Tykwer
导演了电影Cloud Atlas
。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person), (m:Movie) WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas' CREATE (p)-[:DIRECTED]->(m) $$) AS (result1 agtype);
使用MERGE避免插入重复数据
当相同的CREATE 语句执行多次时,将插入多条重复的数据。为避免此类重复数据的产生,可使用MERGE
关键字进行插入。MERGE
进行选择或插入操作,首先会检查数据是否已存在于数据库中。如果数据存在,则会原样返回该数据,或者对现有的节点或关系进行相应的更新。如果数据不存在,Cypher将根据指定的信息进行创建。
语法如下:
SELECT * FROM cypher('<graph_name>', $$
MERGE <patterns>
$$) AS (result1 agtype);
示例:
创建一个标签为
Person
的节点,其中,属性的名字叫Tom Cruise
,出生时间为1962
。SELECT * FROM cypher('moviedb', $$ MERGE (:Person {name: 'Tom Cruise', born: 1962}) $$) AS (result1 agtype);
创建
Tom Hanks
和Tom Cruise
的边,表示朋友关系。SELECT * FROM cypher('moviedb', $$ MATCH (t1:Person),(t2:Person) WHERE t1.name='Tom Hanks' AND t2.name='Tom Cruise' MERGE (t1)-[:FRIEND]-(t2) $$) AS (result1 agtype);
更新
对于数据中已经存在节点或关系,可以通过匹配所需查找的模式修改其属性,并使用SET关键字来添加或更新属性以完成此操作。
语法如下:
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
SET <property>
RETURN <variable>
$$) AS (result1 agtype);
示例:
将Person
Tom Tykwer
出生年份改为1970年。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1965}) SET p.born = 1970 RETURN p $$) AS (result1 agtype);
为Person
Tom Tykwer
添加一个性别属性为male
。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1970}) SET p.gender = 'male' RETURN p $$) AS (result1 agtype);
删除
在Cypher中,使用DELETE
关键字来删除节点和边。
删除边
删除边需要使用MATCH
关键字找到符合模式的边,然后使用DELETE
关键字进行删除。
语法
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result1 agtype);
示例
删除Person Tom Tykwer
和电影Cloud Atlas
的导演边关系。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person)-[r:DIRECTED]->(m:Movie)
WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas'
DELETE r
$$) AS (result1 agtype);
删除节点
删除节点,同样需要使用MATCH
关键字找到符合条件的节点,然后使用DELETE
关键字进行删除。
语法
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result1 agtype);
示例
删除Person Tom Tykwer
。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Tykwer', born: 1970})
DELETE p
$$) AS (result1 agtype);
删除节点及边
当节点存在相应的边时,不允许直接删除该节点。可以使用DETACH DELETE
语法删除该节点的边关系,并删除当前节点。
语法
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DETACH DELETE <variable>
$$) AS (result1 agtype);
示例
删除Person Tom Hanks
以及其关联的边。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Hanks', born: 1956})
DETACH DELETE p
$$) AS (result1 agtype);
删除属性
当不再需要节点或边的属性时,可以使用REMOVE关键字删除该属性。
语法
SELECT * FROM cypher('<graph_name>', $$
MATCH <match_pattern>
REMOVE <property>
$$) AS (result1 agtype);
示例
删除电影Cloud Atlas
的released
属性。
SELECT * FROM cypher('moviedb', $$
MATCH (m:Movie {title: 'Cloud Atlas', released: 2012})
REMOVE m.released
RETURN m
$$) AS (result1 agtype);
可视化工具
使用AGE项目提供图数据可视化工具,可将查询结果进行图形化的表达。详情请参考可视化工具。
- 本页导读 (1)
- 前提条件
- 基本概念
- 模式
- 属性
- 节点
- 边
- 示例
- 创建插件
- 设置数据库
- 查询结构
- 创建图
- 插入数据
- 查询数据
- 创建节点或边
- 使用MERGE避免插入重复数据
- 更新
- 删除
- 可视化工具