基本概念
1.1 图(Graph)
图是由节点和边组成的数据结构。例如,社交网络就是一个典型的图,其中每个人都是一个节点,他们之间的关系(如朋友、家人、同事等)就是边。
1.2 节点(Node)
节点是图数据库中的基本元素,表示数据库中的实体。节点可以具有属性,用于存储与实体相关的信息。例如,在一个社交网络中,节点可以表示用户、公司、组织等实体。
1.3 边(Edge)
边是连接节点的关系。边可以具有权重、方向等属性,用于表示关系的强度和方向。例如,在一个社交网络中,边可以表示用户之间的关注、好友、粉丝等关系。
1.4 标签(Label)
标签是一种用于标识节点或边的分类或属性。标签帮助用户语义化数据,以便更容易地进行查询和理解。例如,在社交网络中,节点的分类可以是人(Person), 或公司(Company), 边的标签可以是认识(Knows)或工作与(WorkIn)等
1.4 属性图
如果节点包含属性(包含有关主题的详细信息)或边包含属性(关系的详细信息),则称为属性图:
以下为一个同事关系的属性图,节点和边上都带有相关的属性:
1.5 图数据库
图数据库(Graph Database)是一种特殊的数据库,使用图来存储数据,节点(Node)表示实体,边(Edge)表示关系。
图数据库非常适合处理复杂的关系数据,如社交网络、信任网络、知识图谱等。
图数据库使用图查询语言(Graph Query Language)来查询数据,如Cypher、Gremlin等。PolarDB兼容OpenCypher语法。OpenCypher是Cypher的一个开源子集,其大部分特性可以认为等同于Cypher,因此如果对于Cypher语法有一定基础可以快速上手。
模式
2.1 属性
Cypher 中使用一对花括号{}来表示属性。 属性是由Key-Value键值对组成,和常见的JSON结构类似。键名是一个字符串;属性值可以是字符串,数值,也可以是一个数组。例如:{name: 'Reeves'}
表示名字叫Reeves
2.2 节点
Cypher 使用一对括号()
来表示节点,以下是一些节点表示的示例:
() (matrix) (:Movie) (matrix:Movie) (matrix:Movie {title: 'The Matrix'}) (matrix:Movie {title: 'The Matrix', released: 1997})
- 最简单的形式,
()
,表示一个匿名的、未表征的节点。 - 如果想在其他地方引用该节点,可以添加一个变量,例如:
(matrix)
。变量仅限于单个语句。在另一个语句中具有不同的或没有意义。 :Movie
模式声明节点的标签。这允许我们限制模式,防止它匹配其他标签的节点。{title: 'The Matrix'}
节点的属性,例如,属性可用于存储信息和/或限制模式。
2.2 边
Cypher 中使用一对短划线 (--
) 来表示无向边;有向边在一端有一个箭头 (<--
、-->
)。方括号表达式 ([...]
) 可用于添加详细信息。包括变量、属性和类型信息。以下是一些边表示的示例
-- --> -[role]-> -[:ACTED_IN]-> -[role:ACTED_IN]-> -[role:ACTED_IN {roles: ['Neo']}]->
- -- 表示一个匿名的无向边
- -->,表示一个匿名的有向边
- 可以定义一个变量(例如,
role
),以便在语句的其他地方使用。 - 关系的标签(例如,
:ACTED_IN
)类似于节点的标签。 - 属性(例如,
roles: ['Neo']
)与节点属性定义方法一致。
示例
以下以一个简单的示例来展示PolarDB中图的基本使用方法。示例数据为一个简单的电影数据库,包含演员和电影的相关信息。
3.1 创建插件
在使用前需要先在PolarDB数据库中创建插件
CREATE EXTENSION age;
3.2 设置数据库
对于每次连接,都需要将 `ag_catalog` 添加到 `search_path` 以简化查询,并通过get_cypher_keywords 函数实现插件的加载:
SET search_path = "$user", public, ag_catalog; 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
要允许普通用户使用AGE:
- 授予
USAGE
权限给所需的用户(例如db_user
)在ag_catalog
模式上:
GRANT USAGE ON SCHEMA ag_catalog TO db_user;
如果用户只是RW用户,需要增加赋予创建表CREATE的权限
GRANT CREATE ON DATABASE db_name TO db_user;
3.3 查询结构
PolarDB 中Cypher 查询是通过调用 ag_catalog
中的一个名为 cypher
的函数构建的,该函数返回一个 SETOF records。
一个典型的查询如下所示:
SELECT * FROM cypher('graph_name', $$ /* 在此处编写 Cypher 查询 */ $$) AS (result1 agtype, result2 agtype);
其中 graph_name 是图的名称,/* */ 内部分可使用实际Cypher进行替代
3.4 创建图
图使用时首先需要创建图。创建图请使用位于 ag_catalog
命名空间中的 create_graph
函数。
PolarDB中写法如下:
SELECT * FROM create_graph('<graph_name>');
- 示例: 创建一个叫moviedb的图
SELECT * FROM create_graph('moviedb');
注意事项
- 此函数不会返回任何结果。如果没有错误消息,则表示图已创建成功。
3.5 插入数据
使用以下的SQL语句向图中插入示例数据:
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)
关系图如下所示:
3.6 查询数据
3.6.1 查询数据
Cypher中使用MATCH + RETURN这两个关键字实现数据的查询。其中:
- MATCH实现的是模式匹配,用于寻找与指定模式来相同的内容。
- RETURN关键字指定希望从Cypher查询返回的值或结果。
PolarDB上一个典型的查询如下所示:
SELECT * FROM cypher('graph_name', $$ MATCH <patterns> RETURN <variables> $$) AS (result1 agtype);
- 示例1: 查找标有“Movie”标签的所有节点。
SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) RETURN m $$) AS (result1 agtype);
- 示例2: 查找标签为ACTED_IN的连接Person和Movie的边
SELECT * FROM cypher('moviedb', $$ MATCH (:Person)-[r:ACTED_IN]->(:Movie) RETURN r $$) AS (result1 agtype);
3.6.2 过滤数据
当图中进行了模式匹配,只需要返回感兴趣的数据子集时,可以使用where子句。该子句允许使用布尔表达式来对子集进行过滤。
- 示例1 查找标题为'The Matrix'的所有电影。
SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) WHERE m.title = 'The Matrix' RETURN m $$) AS (result1 agtype);
- 示例2 查找标题为'Forrest Gump'的所有演员。
SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.title = 'Forrest Gump' RETURN p $$) AS (result1 agtype);
示例3 查询发布时间晚于2000年的电影的演员。
SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.released > 2000 RETURN p, m $$) AS (result1 agtype, result2 agtype);
3.7 创建
Cypher中可以使用关键字CREATE 创建一个全新的节点或边。
PolarDB上一个典型的查询如下所示:
SELECT * FROM cypher('graph_name', $$ CREATE <patterns> $$) AS (result1 agtype);
- 示例1: 创建一个标签为Person的节点,其中属性的名字叫 Tom Tykwer,出生时间为1965
SELECT * FROM cypher('moviedb', $$ CREATE (:Person {name: 'Tom Tykwer', born: 1965}) $$) AS (result1 agtype);
- 示例2: 创建一个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);
3.7.1 使用 MERGE 避免重复数据
当相同的CREATE 语句执行多次时,会插入多条重复的数据。为避免此类重复数据,可使用MERGE
关键字进行插入。MERGE
执行“选择或插入”操作,首先检查数据是否存在于数据库中。如果存在,则会按原样返回它,或者对现有节点或关系进行指定的任何更新。如果数据不存在,则 Cypher 会使用您指定的信息创建它。
PolarDB上一个典型的查询如下所示:
SELECT * FROM cypher('graph_name', $$ MERGE <patterns> $$) AS (result1 agtype);
- 示例1: 创建一个标签为Person的节点,其中属性的名字叫 Tom Cruise,出生时间为1962
SELECT * FROM cypher('moviedb', $$ MERGE (:Person {name: 'Tom Cruise', born: 1962}) $$) AS (result1 agtype);
- 示例2: 在'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);
3.8 更新
数据中可能已经存在节点或关系,修改其属性,可以通过匹配要查找的模式并使用SET关键字添加、更新属性来完成此操作。
PolarDB上一个典型的查询如下所示:
SELECT * FROM cypher('graph_name', $$ MATCH <patterns> SET <property> RETURN <variable> $$) AS (result1 agtype);
- 示例1: 将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);
- 示例2: 添加 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);
3.9 删除
Cypher 中使用 DELETE
关键字来删除节点和关系。
3.9.1 删除关系
要删除关系,需要使用MATCH关键字找到符合模式的关系,然后使用 DELETE
关键字进行删除
PolarDB上一个典型的查询如下所示:
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);
3.9.2 删除节点
要删除节点,同样需要使用MATCH关键字找到符合条件的节点,然后使用 DELETE
关键字进行删除
PolarDB上一个典型的查询如下所示:
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);
3.9.3 删除节点及关系
当节点还有相应的边存在时,节点不允许被删除。可以使用 DETACH DELETE
语法 删除该节点具有的边关系,以及删除节点本身。
PolarDB上一个典型的查询如下所示:
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);
3.9.4 删除属性
当节点或边的属性不再需要时,可通过REMOVE关键字将该属性进行删除
PolarDB上一个典型的查询如下所示:
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项目自带的图数据可视化工具,可将查询结果进行图形化的表达。