Operational Property Graphs到底是个啥?

Operational Property Graphs,中文通常译为"操作属性图"。

作为23ai中被官方highlight出的新特性之一,我们先看下官方的原文描述:

  • Operational Property Graphs in SQL

Developers can now build real-time graph analysis applications against operational

data directly in the Oracle Database, utilizing its industry leading security, high

availability and performance capabilities.

简单说,开发者可以直接在Oracle 23ai中进行实时图分析,而不需要额外的图数据库。

为了不纯扯概念,更好的直观体验,下面我们直接按照官方文档给出的一个简单示例来动手练习体验下:

本次测试环境: Oracle Database 23ai(23.4.0.24.05)
本次用到技术: 原生JSON数据类型、操作属性图。
本次测试意义: 直观体验Oracle数据库多模、融合的设计理念所带来的便利性。

  • 1.准备测试表和测试数据
  • 2.创建属性图
  • 3.体验SQL查询属性图

1.准备测试表和测试数据

这里创建的示例,整体构成了一个基本的数据库结构,测试表 university、persons、students、friendships 分别用于存储大学、人员、学生和朋友关系的数据。

特别需要注意的是,persons 表中的 person_data 字段是 JSON 类型,用于存储原生 JSON 数据。这也是23ai在其多模能力上的一种体现,使其能够更适合用来构建现代的应用平台。

复制代码
-- 1.CREATE TABLE university
CREATE TABLE university (
    id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
    name VARCHAR2(10),
    CONSTRAINT u_pk PRIMARY KEY (id));
    
INSERT INTO university (name) VALUES ('ABC');
INSERT INTO university (name) VALUES ('XYZ');
commit;

-- 2.CREATE TABLE persons
-- 包含存放原生的JSON数据类型字段person_data,这里是存放了这个人的部门信息和岗位角色
CREATE TABLE persons (
     person_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT
     BY 1),
     name VARCHAR2(10),
     birthdate DATE,
     height FLOAT DEFAULT ON NULL 0,
     person_data JSON,
     CONSTRAINT person_pk PRIMARY KEY (person_id)
   );

INSERT INTO persons (name, height, birthdate, person_data)
       VALUES ('John', 1.80, to_date('13/06/1963', 'DD/MM/YYYY'), '{"department":"IT","role":"Software Developer"}');
INSERT INTO persons (name, height, birthdate, person_data)
       VALUES ('Mary', 1.65, to_date('25/09/1982', 'DD/MM/YYYY'), '{"department":"HR","role":"HR Manager"}');
INSERT INTO persons (name, height, birthdate, person_data)
       VALUES ('Bob', 1.75, to_date('11/03/1966', 'DD/MM/YYYY'), '{"department":"IT","role":"Technical Consultant"}');
INSERT INTO persons (name, height, birthdate, person_data)
       VALUES ('Alice', 1.70, to_date('01/02/1987', 'DD/MM/YYYY'), '{"department":"HR","role":"HR Assistant"}');
commit;

-- 3.CREATE TABLE students
-- 这里官方文档有个错误,属于低级错误,插入字段数量和具体赋值对应不上,此处已修正
CREATE TABLE students (
      s_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
      s_univ_id NUMBER,
      s_person_id NUMBER,
      subject VARCHAR2(10),
      CONSTRAINT stud_pk PRIMARY KEY (s_id),
      CONSTRAINT stud_fk_person FOREIGN KEY (s_person_id) REFERENCES persons(person_id),
      CONSTRAINT stud_fk_univ FOREIGN KEY (s_univ_id) REFERENCES university(id)
    );

INSERT INTO students(s_univ_id, s_person_id, subject) VALUES (1,1,'Arts');
INSERT INTO students(s_univ_id, s_person_id, subject) VALUES (1,3,'Music');
INSERT INTO students(s_univ_id, s_person_id, subject) VALUES (2,2,'Math');
INSERT INTO students(s_univ_id, s_person_id, subject) VALUES (2,4,'Science');
commit;

-- 4.CREATE TABLE friendships
-- 这里 meeting_date 可理解为朋友之间相遇的日期
CREATE TABLE friendships (
    friendship_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
    person_a NUMBER,
    person_b NUMBER,
    meeting_date DATE,
    CONSTRAINT fk_person_a_id FOREIGN KEY (person_a) REFERENCES persons(person_id),
    CONSTRAINT fk_person_b_id FOREIGN KEY (person_b) REFERENCES persons(person_id),
    CONSTRAINT fs_pk PRIMARY KEY (friendship_id)
);

INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (1, 3, to_date('01/09/2000', 'DD/MM/YYYY'));
INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (2, 4, to_date('19/09/2000', 'DD/MM/YYYY'));
INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (2, 1, to_date('19/09/2000', 'DD/MM/YYYY'));
INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (3, 2, to_date('10/07/2001', 'DD/MM/YYYY'));
commit;

2.创建属性图

复制代码
-- 5.CREATE PROPERTY GRAPH students_graph
-- 这里是关键的属性图创建:
CREATE PROPERTY GRAPH students_graph
  VERTEX TABLES (
    persons KEY (person_id)
      LABEL person
        PROPERTIES (person_id, name, birthdate AS dob)
      LABEL person_ht
        PROPERTIES (height),
    university KEY (id)
  )
  EDGE TABLES (
    friendships AS friends
      KEY (friendship_id)
      SOURCE KEY (person_a) REFERENCES persons(person_id)
      DESTINATION KEY (person_b) REFERENCES persons(person_id)
      PROPERTIES (friendship_id, meeting_date),
    students AS student_of
      SOURCE KEY (s_person_id) REFERENCES persons(person_id)
      DESTINATION KEY (s_univ_id) REFERENCES university(id)
      PROPERTIES (subject)
  );

这个对于DBA出身的小伙伴们来说,可能会很陌生,也稍难理解些。所以这里详细解释说明下:

上面的SQL语句是在Oracle数据库中,直接创建了一个属性图students_graph,具体包含两个顶点表(persons和university)和两个边表(friendships和students)。

那什么是顶点表?边表又是啥?

在图数据库中,顶点(Vertex)和边(Edge)是构建图数据模型的基本元素:

顶点表(Vertex Table):表示图中的实体或对象。

边表(Edge Table):表示图中的关系或连接,定义了两个顶点之间的关系。

具体在我们这个例子中,顶点表personsuniversity表示人员和大学。

边表friendshipsstudents表示人员之间的友谊关系和人员与大学之间的学生关系。

了解了基本概念后,再回过头来看这个SQL定义的属性图,拆解分析后是不是很清晰了呢?

  • VERTEX TABLES(顶点表)

    -- persons 表:
    KEY (person_id):指定主键。
    LABEL person:给顶点赋予person标签。
    PROPERTIES (person_id, name, birthdate AS dob):指定属性,其中birthdate属性重命名为dob。
    LABEL person_ht:给顶点赋予person_ht标签。
    PROPERTIES (height):指定属性height。

    -- university 表:
    KEY (id):指定主键。

  • EDGE TABLES(边表)

    -- friendships 表(别名friends):
    KEY (friendship_id):指定主键。
    SOURCE KEY (person_a) REFERENCES persons(person_id):源顶点引用persons表的person_id。
    DESTINATION KEY (person_b) REFERENCES persons(person_id):目标顶点引用persons表的person_id。
    PROPERTIES (friendship_id, meeting_date):指定属性。

    -- students 表(别名student_of):
    SOURCE KEY (s_person_id) REFERENCES persons(person_id):源顶点引用persons表的person_id。
    DESTINATION KEY (s_univ_id) REFERENCES university(id):目标顶点引用university表的id。
    PROPERTIES (subject):指定属性。

3.体验SQL查询属性图

实际使用了Oracle的图表查询语言来查找名为"John"的人的朋友,并返回这些朋友的名字。

复制代码
SELECT *
FROM GRAPH_TABLE ( students_graph
  MATCH (a IS person) -[e IS friends]- (b IS person)
  WHERE a.name = 'John'
  COLUMNS (b.name)
);

这个SQL同样会让DBA觉得不适应,看起来怪怪的,但对开发人员应该很容易理解了。为了让DBA出身的小伙伴们也能理解,我们继续逐一来解释:

复制代码
-- FROM GRAPH_TABLE:
使用 GRAPH_TABLE 函数来查询图数据。

-- students_graph:
这是之前创建的属性图的名称。

-- MATCH (a IS person) -[e IS friends]- (b IS person):
MATCH:定义图的模式。
    (a IS person):匹配标签为 person 的顶点 a。
    -[e IS friends]-:匹配标签为 friends 的边 e,连接顶点 a 和 b。
    (b IS person):匹配标签为 person 的顶点 b。

-- WHERE a.name = 'John':
过滤条件:顶点 a 的 name 属性为 'John'。

-- COLUMNS (b.name):
定义返回的列:返回顶点 b 的 name 属性。

当然,除了返回朋友的名字,还可以返回更多信息,比如和这位朋友友谊开始的日期:

复制代码
SELECT *
FROM GRAPH_TABLE ( students_graph
  MATCH (a IS person) -[e IS friends]- (b IS person)
  WHERE a.name = 'John'
  COLUMNS (b.name, e.meeting_date)
);

只是在COLUMNS条件中,增加了e.meeting_date,是不是咋一看很晦涩难懂,实际理解了,其实跟普通SQL一样的简单清晰呢?

上面示例的两个SQL的查询结果如下:

复制代码
23:02:23 PRIMARY @ORCL -> JINGYU @PDB1> SELECT *
FROM GRAPH_TABLE ( students_graph
  MATCH (a IS person) -[e IS friends]- (b IS person)
  WHERE a.name = 'John'
  COLUMNS (b.name)
);23:02:23   2  23:02:23   3  23:02:23   4  23:02:23   5  23:02:23   6

NAME
----------
Mary
Bob

Elapsed: 00:00:00.00
23:02:24 PRIMARY @ORCL -> JINGYU @PDB1> SELECT *
FROM GRAPH_TABLE ( students_graph
  MATCH (a IS person) -[e IS friends]- (b IS person)
  WHERE a.name = 'John'
  COLUMNS (b.name, e.meeting_date)
);23:02:35   2  23:02:35   3  23:02:35   4  23:02:35   5  23:02:35   6

NAME	   MEETING_D
---------- ---------
Mary	   19-SEP-00
Bob	   01-SEP-00

Elapsed: 00:00:00.01
23:02:35 PRIMARY @ORCL -> JINGYU @PDB1>

清理实验环境:

删除本次测试的表和属性图,方便快速清理环境或重新测试:

复制代码
-- 先删除有外键约束的表:
drop table students purge;
drop table friendships purge;

-- 再删除其他表:
drop table university purge;
drop table persons purge;

-- 删除属性图:
drop PROPERTY GRAPH students_graph;

参考的官方文档链接:

注:官方文档给出的例子有些小问题,已在文章中代码部分修正,方便大家直接复制粘贴文中代码来进行快速测试验证。

最后总结一下本文都涵盖了哪些内容:

  • 例子中提到的原生JSON数据类型,其实还比较容易理解,无非就是把JSON数据存储到对应这个数据类型的字段中。注意这里并没有提到JSON关系二元性,这个话题以后空了再单独研究讨论。

  • 有个细节,创建表语句中使用的自增id,GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),这其实不算是一个很新的功能,但如果读者对Oracle的认知还停留在11g时代,可能还会认为Oracle不支持类似像MySQL这种自增ID的设计,需要序列配合实现。而实际上,早在12c之后就已经支持了这种方式。

  • 介绍并演示操作属性图这个特性。

回到本文实验的主题,操作属性图(Operational Property Graphs)其实对传统偏管理方向的DBA来说,理解上还是有一些技术挑战的。

比如开始很可能照例子创建成功了,也不知道如何用,创建出来的属性图想直接查询看到底是个啥内容,发现自己还不会正确的使用语法。

笔者也是,但静下心来,花些时间看看文档,理解这类新特性之后,就会发现其强大之处,也容易积极推广给有需要的开发人员来使用,实现简化开发,降低使用属性图的门槛,提升工作效率。

相关推荐
Irissgwe6 天前
十、LangGraph能力详解(2)LangGraph入门教程,构建AI工作流
ai·langchain·graph·langgraph
小码农叔叔2 个月前
【微服务】Spring AI Alibaba Graph 多智能体AI工作流开发实战详解
graph·graph 详解·graph 使用·graph 使用详解·graph 总结·graph工作流编排
シ風箏2 个月前
GraphRAG【部署 01】Linux环境安装部署GraphRAG并使用Ollama本地大模型
·知识库·graph·rag·graphrag·图知识库
组合缺一5 个月前
灵动如画 —— 初识 Solon Graph Fluent API 编排
java·solon·graph·flow·langgraph·liquor
flying_13147 个月前
图神经网络分享系列-GraphSage(Inductive Representation Learning on Large Graphs) (二)
图神经网络·gnn·graph·gcn·graphsage
pedestrian_h8 个月前
AI大模型框架eino框架快速上手
ai·golang·大模型·graph·eino
斯内科1 年前
C#将【程序集引用-依赖关系】展示到NetronLight图表中
c#·流程图·graph
dingdingfish1 年前
Oracle 数据库 23ai 新特性:Use Case Domain
oracle·database·domain·23ai
Florian1 年前
Qwen3接入评测,最强开源模型更懂Graph了吗?
agent·graph·chat2graph·qwen3
维度攻城狮1 年前
高效创建工作流,可实现类似unreal engine的蓝图效果,内部使用多线程高效执行节点函数
python·游戏引擎·开源软件·虚幻·graph·工作流