嬴图 | 微距观察从“表数据”到“图数据”的建模过程

news2024/12/25 0:32:23

前言

随着图数据库{1}技术在工业领域的有效开展和深入应用,在建模时,到底“图数据”与“表数据”有哪些不同?本文,笔者以搭建一个简单的医院信息管理系统为例,具体对比并阐述了用关系型查询语言SQL和图查询语言UQL(Ultipa GQL)在结构设计、查询语句和呈现结果上的不同。同时,希望这些思考也能带给更多的图开发者、使用者、决策者以及爱好者些许启迪,欢迎大家留言交流。

01 | 表 VS.图

我们知道,在图数据库的知识领域,开发人员注重深耕图查询语言【更多了解,点击阅读:文库 | 图数据库基础知识—贰】的运用,解决方案人员更关心图算法,管理员则专注于图数据库的维护和管理。今天我们来深入探讨系统架构师所关心的核心议题——图建模,这个过程涉及到如何定义不同类型的节点{}2{3}

图建模的过程类比到关系型数据库中就是表的构建过程。许多图数据库的用户都面临一个共同的难题:如何将项目中的数据从传统的关系型数据库顺利迁移到图数据库中。当初学者们面对包含上百个字段的数十张关系表时,并不确定这些表应该被转化为节点还是边,哪些字段应该被保留为属性,哪些则应该被抽离成为节点或边。

考虑到每张关系表和每个点/边schema(模式)本质上都是结构化的,我们可以首先将表定义为schema,然后将表内字段定义为schema的属性。这种抄作业似的图模型设计虽然操作简单,但必将在后续图查询时暴露出不足之处。

事实上,一张关系表需要历经多个改造步骤,才能真正成为中的一个schema。在这个改造过程中,我们需要特别关注原先表的主键和外键,因为它们将在未来成为节点ID以及边的起点和终点。

让我们站在操作者的视角,分别使用SQL Server和Ultipa Graph搭建一个简单的医院信息管理系统。

02 |(一)SQL Server 建表

1、表的结构设计

假设一个医院信息管理系统需要记录最基本的医生接诊、患者住院等日常工作内容,依托SQL Server构建的该系统需要存储以下几个关系表:

(1) 科室表(科室名,科电话,科地址)

(2) 病床表(病房号,床位号科室名

(3) 医生表(医生工号,医生姓名,年龄,科室名,职称)

(4) 患者表(病历号,患者姓名,性别)

(5) 诊治记录表(病历号,诊断时间,主治医生,诊断结果)

(6) 住院登记表(病历号,入院时间,病房号,床位号

其中单下划线的字段(红色)代表主键,单下划线的字段(绿色)代表外键。这里我们进行了一个巧妙的处理,就是让字段“科室名”在科室表中既充当科室的名称,又作为主键使用。

这种设计的好处在于,当病床表和医生表引入外键“科室名”时,无需再增加一个用于记录科室名称的冗余字段。通过这个外键,我们能够直接获取科室的名称,避免了额外的表连接查询,提高了系统效率和性能。

然而在诊治记录表中,情况就没这么便利了。该表中的字段“主治医生”选取的是医生表中的“医生姓名”,而非“医生工号”,因此该字段不能作为外键使用。

这意味着,在查询诊治信息时,我们只能看到主治医生的姓名,如果希望获得更多医生的信息,如所属科室、职称,就需要在诊治记录表中添加外键“医生工号”,并进行表连接查询后才能获知。针对诊治记录表缺少外键的这一情况,我们暂时不进行修正,而是在后续与图结构进行对比时再回过来讨论这个问题。

2、表的创建

按照设计好的结构,依次将这6个表创建到SQL Server的某个库中。为了突出重点,我们省略了建表的SQL语句,直接将创建后的表头展示如下:

(1) 科室表(科室名,科电话,科地址)

(2) 病床表(病房号,床位号,科室名)

(3)医生表(医生工号,医生姓名,年龄,科室名,职称)

(4) 患者表(病历号,患者姓名,性别)

(5) 诊治记录表(病历号,诊断时间,主治医生,诊断结果)

(6) 住院登记表(病历号,入院时间,病房号,床位号,)

3、数据插入

接下来我们将一些测试数据插入到这些表中,为了节省篇幅也不展示SQL代码了,直接来看插入后的结果:

(1)科室表

(2)病床表

(3)医生表

(4)患者表

(5)诊治记录表

(6)住院登记表

不可否认,表数据的呈现方式虽然机械,但其列表形式的确可以详细地展示每个字段的信息。然而对于表间关系,如“哪个科室的医生诊治了哪个病人”或“哪个病人入住了哪个科室的哪个病房”,表数据就没法进行直观表达了。与接下来将要构建的图数据相比,这种差异将格外明显。

03 | Ultipa Graph 构图

1、图的结构设计

图模型的设计并不需要一蹴而就,我们先基于之前的表结构初步定义节点和边:

(1) 科室-点(科室名,科电话,科地址)

(2) 病床-点(病房号,床位号,科室名)

(3) 医生-点(医生工号,医生姓名,年龄,科室名,职称)

(4) 患者-点(病历号,患者姓名,性别)

(5) 诊治-边(病历号,诊断时间,主治医生工号,诊断结果)

(6) 入住-边(病历号,入院时间,病房号,床位号

在这个图模型中,我们将科室、病床、医生、患者定义成了点,下划线(红色)的信息代表点的ID。同时,诊治、入住被定义成了边,下划线(蓝色)的信息代表边的起点、终点。

通过与之前的表格进行对比,我们可以明显看到一些差异。例如:

由于表(5)和表(6)被设计成了图中的边,我们不再关注它们原来的ID,也就是表的主键,而是将注意力放在了边的起点和终点上。

边的起点和终点通常以点的ID来表示,如果放回到原来的表中,它们是可以充当外键的。

对于表(6),其“病历号”和“床位号”分别代表患者和病床的ID,因此表(6)可以直接设计为诊治边。

但对于表(5),我们需要将原来表示医生姓名的字段“主治医生”替换为代表医生ID的“主治医生工号”。

这个修改同时回应了前文中提到的外键缺失问题。此前,我们将外键缺失问题遗留在了表中,而现在,我们在边上对其进行纠正。

需要注意的是,虽然节点的ID沿用了之前表结构中的字段名,但它们并不是同一个概念。这是因为在Ultipa图系统中,节点的ID必须在整个图中是唯一的,而不仅仅在某一种类型的节点之间唯一,也就是说不同类型的点(科室、病床、医生、患者)的ID均不同。相比之下,关系型数据库中的主键仅在表内唯一,而不需要在整个数据库中唯一。这个区别会对将节点和边数据插入图中时的一些操作细节产生影响。

2、建立schema和属性

将图数据库中的点、边的不同“类型”理解为schema,将每种类型应记录的信息理解为属性,那么图数据库的创建schema和属性的过程就相当于关系型数据库的建表过程。

根据前文提供的图模型,我们本应创建4个点schema和2个边schema。然而为了更贴合实际情况,我们还需要做一些改进。首先,将病房的信息从病床中抽离出来,成为一个独立的schema。这个改进将有助于更有效的统计和管理病房空余床位等信息。改进后的5个点schema分别为:

(1) 科室-点(科室名,科电话,科地址)

(2) 病房-点(病房号科室名

(3) 病床-点(床位号病房号

(4) 医生-点(医生工号,医生姓名,年龄,科室名,职称)

(5) 患者-点(病历号,患者姓名,性别)

我们特意使用单下划线(绿色)标识了一些属性,这些属性相当于关系型数据库中的外键。将这5个点schema创建到Ultipa 图数据库的某个图集中,它们在Ultipa Manager中展示为:

细心的读者可能会注意到,我们似乎只创建了一部分属性,点的ID还有双下划线标识的“外键”并未出现在属性列表中。

这有两个原因:

其一,红色的点ID作为Ultipa图集中的系统属性是由系统生成的,其属性名为_id,并且不会在Ultipa Manager的属性列表中显示,因此我们无法直接看到它。

其二,绿色的“外键”在图中通常以边的形式存在,我们可以将病房归属于科室、病床归属于病房、医生归属于科室这三类关系创建为某种边schema。

从另一个角度来看,在图数据库的设计中,我们不鼓励引入关系型数据结构中常见的所谓的“冗余信息”,因为借助图数据库强大的关联查询与计算能力,信息之间的关联关系可以轻松通过路径查询获取,而无需冗余数据。

点schema改进后,边schema也要相应调整。这里指的就是为上述三种“属于”关系添加一种schema:

(1) 诊治-边(病历号,诊断时间,主治医生工号,诊断结果)

(2) 入住-边(病历号,入院时间,病房号床位号

(3) 属于-边(病房号/床位号/医生工号科室名/病房号/科室名

对于边schema我们同样用双下划线标识了一个“外键”。继续在当前所用的图集中创建这3个边schema:

就像我们在创建点schema时遵循的原则一样,创建边schema时也采取了一些"省略"措施:

其一,蓝色的边起点和边终点,这两个系统属性同样由系统自动生成,并且不会在Ultipa Manager的属性列表中显示。

其二,绿色的入住外键“病房号”可以根据“床位属于病房”的关系自动推导,因此无需将其创建为属性。这种能够减少冗余信息的简化,当然也是利用了图数据库强大的关联查询功能。

3、插入数据

使用Ultipa Manager导入图数据时,系统支持上传UTF-8编码的CSV文件。在制作这些文件时,需要特别注意之前提到的点ID与主键的区别。某些时候,需要对表数据的主键进行全图唯一编码,才能生成有效的点ID。

此外,由于Ultipa图系统要求边的起点和终点必须是已经存在于图集中的点,因此必须先导入节点数据,再导入边的数据。

在成功导入所有数据后,Ultipa Manager中的2D全貌将展现出整个图的结构:

在这张图中,我们运用了丰富的色彩来区分不同的实体。淡紫色的节点代表医生黄色节点代表患者深紫色节点代表科室蓝色节点代表病房绿色节点代表床位诊治边蓝色表示,入住边橙色展示,属于边则以黄色呈现。这些鲜明的颜色使医生、患者、床位等各种实体之间的关系清晰可见,我们只需一瞥就能轻松辨别图中哪些节点之间存在密切联系,甚至可以追溯到某个病床对应的患者的主治医生是谁。图数据库在可视化方面的这种直观性和便捷性让关系型数据库望尘莫及。

04 | SQL和UQL 查询的对比

拥有先进技术支持的图数据库在查询方面自然胜过关系型数据库,对于初学者,即使尚未深入理解底层技术的奥妙,也能从代码编写和查询速度等方面明显感受到这种差距。由于这次实践所准备的测试数据较小,让我们先搁置查询速度的探讨,直接比较关系型数据库的SQL和图数据库的UQL在编写特定查询时的差异。 具体的查询需求是:寻找医生王五接诊的患者的信息、诊断结果,并显示医生姓名。

SQL代码:

SELECT 患者表.PNO, 患者表.PNAME, 患者表.PSEX, 诊治记录表.DIAGONSRESULT, 诊治记录表.DNAME FROM 诊治记录表 JOIN 患者表 ON 诊治记录表.PNO = 患者表.PNO WHERE DNAME = '王五'

SQL运行结果:

UQL代码:

n({@`医生`.`姓名` == "王五"} AS D).e({@`诊治`} AS A).n({@`患者`} AS P) RETURN table(P._id, P.`姓名`, P.`性别`, A.`结果`, D.`姓名`)
UQL运行结果:

SQL和UQL的运行结果完全一致,但对比这两段代码时,我们发现了一件有趣的事情。SQL采用英文语序,对于以汉语思维为主的人来说,它是一种颠倒的表达方式。

在本次所举的例子中,SQL先使用SELECT声明要返回的数据列,然后用FROM JOIN说明这些列来自于哪些表的连接结果,同时用ON来强调这些表是基于哪些主键进行连接的,最后通过WHERE来指定条件,对连接后表中的数据行进行筛选。

我们常常强调,形成编程思维方式意味着开发者需要放下自己的母语表达习惯,遵循编程语言的语法规则来进行表达。这种思维方式的转变通常是学习编程语言时的最大挑战之一。

那么,什么样的编程语言语法能够最好地平衡不同人之间语言、思维模式的差异呢?

让我们深入研究一下这段UQL代码:首先,它使用了一个n().e().n()路径模板,精简描述了医生与患者之间的诊治关系。之后,它将路径上的各种数据元素组装在一起以供返回。

这段UQL代码将路径中的筛选条件(王五)保留在了路径描述中的,而不是像SQL的WHERE子句那样在事后进行补充说明。这使得UQL更加紧凑和连贯,同时也增强了代码的可读性。由于数据存储结构的不同以及数据建模的差异,UQL将抽象的表连接以及分散的过滤条件巧妙地整合成了一条链式路径模型。

还有一点必须强调,SQL代码中常见的使用ON子句提示的表连接的锚点“主键”在UQL中并未出现,这是因为实体之间的连接关系已经在点和边的定义中内部化了,不需要额外的描述。这种简化和集成的方式使得代码更加清晰,同时也是图数据库针对关联关系的查询效率远高于关系型数据库的根本原因。

UQL的语法不是基于某种特定的自然语言,而是建立在更普遍的思考方式之上——这种思考方式强调事情的处理顺序和基本逻辑。

人类大脑的思考过程常常以一种连锁反应的方式进行联想和推理,每一步都会附带相关的条件。因此,学习UQL的人通常不太会受到语言或文化方面的限制。学习UQL的过程实际上是提高学习者自身高维空间思维和联想能力的过程。

最后,尽管这两段代码返回了相同的结果,但它们实际完成的查询功能并不相同。事实上SQL只实现了患者表和诊治记录表之间的连接,而它返回的“医生姓名”只是诊治记录表中的一个字段。UQL实现的则是患者、诊治、医生之间的关联,相当于在关系型数据库中进行了三张表的连接查询,它所返回的医生姓名是“医生”schema的属性。

如果我们需要增加返回“医生职称”的需求,只需在上述UQL代码的table()函数中添加一个D.`职称`即可实现,而SQL代码则需要再添加一个JOIN ON语句,将医生表也连接进来才能返回医生的职称信息,代码也会更加冗长。

这凸显了UQL在实现相同查询功能时的简洁性与高效性。

我们之所以用表格的形式呈现了UQL语句的查询结果,是为了更好地将其与SQL进行对比。在实际使用UQL进行路径查询时,我们更倾向于以2D/3D的形式来展示结果。当我们将上述UQL代码改写并在Ultipa Manager中运行时,系统会自动以2D模式呈现查询结果,让我们更直观地理解和分析数据。

改写后的UQL代码:

n({@`医生`.`姓名` == "王五"}).e({@`诊治`}).n({@`患者`}) as p RETURN p{*}

05 | 结语

在实际应用场景中,图数据库的图模型构建还会涉及各种错综复杂的情况,而本次实践仅是为了激发对这个话题的初步思考——精心雕琢图模型对于确保高效查询至关重要。图模型的构建必须与未来的查询业务密切协同,并在业务需求发生变化时做出灵活的调整。后续,笔者还将推出系列文章,深入探讨和总结这些微妙之处。毕竟,图模型的精准塑造是高效图应用开发的第一步。

通过此文,笔者也期望能够协助初学者更好地理解并选择适合其需求的数据库,同时为更深入的图数据库学习和探索奠定基础。此外,看文章的你,如果想了解更多关于图数据库与关系型数据库的区别,可点击扩展阅读。

【注释】

[1] 图数据库; https://www.ultipa.cn/document/ultipa-graph-query-language/basic-concepts/v4.0

[2]点 (Node),代表真实世界中的实体,即图论中的顶点 (vertex),在 Ultipa 图系统中也称作节点。

[3] 边 (Edge),代表真实世界中实体间的关系,即连接两个节点的边。Ultipa 图系统中的边均为有向边。边的两个端点可以相同也可以不相同,相同时边称为自环边(Loop)。

【文/孙婉怡;图/王紫嫣】

更多精彩阅读:请点击:Ultipa Graph - 高性能图数据库赋能万物关联

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1066691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云/腾讯云国际站账号:腾讯云国际站特效SDK购买

产品介绍 随着直播、短视频业务的爆发式增长,丰富多样的视频特效,自然生动的智能美颜,新奇有趣的贴纸玩法也受到大量关注,为多种视频场景注入了新的生机与活力。腾讯特效 SDK(Tencent Effect SDK)&#xf…

Node18.x进阶使用总结之MongoDB7.x(三)

Node18.x进阶使用总结之MongoDB7.x 1、MongoDB7.x的安装1.1、下载安装与启动1.2、MongoDB目录1.3、安装MongoDB Shell1.4、设置环境变量1.5、使用MongoDB 2、命令行交互2.1、数据库命令2.2、集合命令2.3、文档命令 3、Mongoose3.1、连接数据库3.2、创建新文档3.3、字段类型3.4、…

vue 百度地图/天地图设置铺满屏幕100%,解决空隙问题

设置100%无效&#xff0c;刷新依然右侧有空隙&#xff0c;解决&#xff1a;min-width: 100vw; <div class"aui-flex-col" style"width: 100%; height:100%"><div id"mapAllCon" style"width: 100%; min-width: 100vw; height: 10…

从0开始python学习-31.selenium 文本输入框、下拉选择框、文件上传、时间插件选择元素定位

目录 1. 纯文本输入框 2. 存在默认值的文本输入 3. 下拉选择框 4. 输入后下拉选择框 5. 文件上传 6. 时间插件 1. 纯文本输入框 driver.find_element(By.XPATH,/html/body/div[2]/td[2]/input).send_keys(测试名称) 2. 存在默认值的文本输入 注意&#xff1a; 1. 这种存…

mkv怎么转换为mp4?

mkv怎么转换为mp4&#xff1f;你是否有过这样的情况&#xff0c;电脑上播放MKV格式的视频文件很流畅&#xff0c;但却无法在手机端或者一些剪辑软件中正常播放以及识别&#xff0c;导致工作效率的降低&#xff1f;这个问题的根本原因在于电脑上的播放器可以兼容MKV格式&#xf…

Java中双冒号“::”到底什么意思

今天给大家分享一个JDK8中的新特性双冒号&#xff1a;”::“&#xff0c;双冒号“::”就是 Java 中的方法引用&#xff0c;是Java 8中的Lambda表达式写法之一&#xff0c;一种执行方法的方法。 在一定程度上简化了我们Java开发的冗余代码。 双冒号(::)使用场景一般有如下6种&a…

物流仓储RFID系统设计案例分享

一、项目背景 为了实现仓储货物管理数字化转型的目标&#xff0c;提升仓储业务自动化和数字化水平&#xff0c;在满足仓储日常需求的基础上&#xff0c;验证物联网和人工智能相关技术能力&#xff0c;为仓储业务的柔性自动化、快速部署和复制提供储备能力。 项目设计目标包括…

c++视觉ROI 区域和ROI 区域图像叠加

ROI 区域提取和ROI 区域图像叠加 ROI 区域提取 #include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat image cv::imread("1.jpg");// 检查图像是否成功加载if (image.empty()) {std::cerr << "Error: Could not read the image." …

hadoop集群安装并配置

文章目录 1.安装JDK 环境2.系统配置2.1修改本地hosts文件2.2创建hadoop 用户2.2 设置ssh免密&#xff08;使用hadoop 用户生成&#xff09; 3.安装 hadoop 3.2.43.1 安装hadoop3.1.1 配置Hadoop 环境变量 3.2配置 HDFS3.2.1 配置 workers 文件3.2.2 配置hadoop-env.sh3.2.3 配置…

【数字化转型】10大数字化转型能力成熟度模型01(IOMM)

一、前言 数字化转型是数据化能力建设的目标和价值&#xff0c;作为一个新兴的课题&#xff0c;目前为止并未出现一个统一的数字化转型成熟度模型。不同的企业和机构&#xff0c;根据自身的发展和认知&#xff0c;推出了自己的企业级或者准行业级标准。这些标准具有很强的参考意…

一本没有任何数学公式的自然语言处理入门书

ChatGPT 时代来了&#xff0c;AI 从旧时王谢堂前燕&#xff0c;飞入寻常百姓家。越来越多非 AI 领域 的软件开发者涌进 NLP(自然语言处理)领域。在这个快速发展的时代&#xff0c;如果这些软件开发 者要像读书那样先读 4 年本科、2 年硕士、3 年博士才能搞 AI&#xff0c;风口早…

Python:温度转换(摄氏度与华氏度)

Python:温度转换&#xff08;摄氏度与华氏度&#xff09; TempStrinput("请输入带有符号的温度值&#xff1a;") if TempStr[-1] in [F,f]:C(eval(TempStr[0:-1])-32)/1.8print("转换后的温度是{:.2f}C".format(C)) elif TempStr[-1] in[C,c]:F1.8*eval(T…

在Android中实现动态应用图标

在Android中实现动态应用图标 你可能已经遇到过那些能够完成一个神奇的技巧的应用程序——在你的生日时改变他们的应用图标&#xff0c;然后无缝切换回常规图标。这是一种引发你好奇心的功能&#xff0c;让你想知道&#xff0c;“他们到底是如何做到的&#xff1f;”。嗯&…

【EI会议征稿】第三届智慧交通、能源与动力国际学术会议(STEP 2023)

第三届智慧交通、能源与动力国际学术会议&#xff08;STEP 2023&#xff09; 2023 3rd International Conference on Smart Transportation, Energy and Power 第三届智慧交通、能源与动力国际学术会议 (STEP 2023) 将于2023年12月15-17日在中国三亚市隆重举行&#xff0c;会议…

使用vite+npm封装组件库并发布到npm仓库

组件库背景&#xff1a;使用elementplusvue封装了一个通过表单组件。通过JSX对el-form下的el-input和el-button等表单进行统一封装&#xff0c;最后达到&#xff0c;通过数据即可一键生成页面表单的功能。 1.使用vite创建vue项目 npm create vitelatest elementplus-auto-form…

Linux基础工具

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; C&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大…

【轻松玩转MacOS】基本操作篇

引言 本文是系列的开篇&#xff0c;我将为大家介绍MacOS的基本操作。对于初次接触MacOS的用户来说&#xff0c;掌握这些基本操作是必不可少的。无论是启动和关机&#xff0c;还是使用键盘和鼠标&#xff0c;或者是快捷键的使用&#xff0c;这些基本操作都是你开始使用MacOS的第…

三星发布 Galaxy SmartTag 2

三星近日发布了一款新品 —— Galaxy SmartTag 2 追踪器&#xff0c;该款产品采用了全新的椭圆设计以取代上代 SmartTag 的菱形设计&#xff0c;这款的钥匙孔也比上代更大&#xff0c;并采用了金属圆环以防止磨损。 这款产品有黑、白2种颜色可供选择&#xff0c;支持 IP67 级防…

网络原理 - 详解

一&#xff0c;网络通信基础 1.1 IP地址 描述一个设备在网络上的地址&#xff0c;一般使用4个0~255之间的数字&#xff0c;并且使用三给 . 进行分割&#xff0c;如&#xff1a;127.0.0.0 1.2 端口号 端口号是一个2个字节的整数&#xff0c;用来区分一个主机上的不同应用程序…

全面解析HTTP协议

当谈到网络通信和Web开发时&#xff0c;HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一个非常重要的协议&#xff0c;它是用于在Web浏览器和服务器之间传输数据的基础协议。 什么是HTTP协议&#xff1f; HTTP是一种应用层协议&#xff0c;用于在客户端和服务器…