本节我们将介绍数据图的各种增强与扩展,包括「模式」(schema)、「身份」(identity)和「上下文」(context),它们为知识的聚合提供了额外的结构。从现在开始,我们用「数据图」(data graphs)指代通过节点和边表示的数据集合,具体形式为上一节提到的任意一种模型;用「知识图谱」(knowledge graphs)指代一个通过模式、身份、上下文、本体(规则)进行过潜在增强的数据图。这些额外的表示可能直接嵌入到数据图中,也可能分层叠加在其之上。本章节将专注于模式、身份和上下文,关于本体与规则会在第四节中讨论。
将数据表示为图的优势之一(与关系模型相比)在于我们可以选择放弃或推迟定义模式(因为图的灵活性)。不过在数据图中,模式可以用于建立一种约束图的「顶层结构」,本小节将讨论三种图模式:「语义」(semantic)、「验证」(validating)和「涌现」(emergent)。
语义模式即定义图中的节点或边所对应的「顶层术语」,以促进基于这些术语的推理。下面将结合上图(上一节中的有向标记图,记为「图 1」)来进行具体说明。我们可以定义「类」(class)来描述一些相似的节点的集合,如 Event
、City
等,通过标签为 type 的边来表示节点所属的类。实际上,上图中已经包含了三个较低层次的类:Open Market
、Food Festival
、Drinks Festival
。为了完善 Event
类的定义,我们提出如下的类层级结构(通过树来表示),其中叶子节点可以理解为其父节点的「子类」(subclass)。基于这种层级结构我们就可以进行简单的推理,如对于 EID15
—type→ Food Festival
,我们可以推理出 EID15
—type→ Festival
以及 EID15
—type→ Event
。
除了类,我们还可以通过「属性」(property)来定义边标签的语义。在图 1 中,我们可以将标签 city 和 venue 看做属性 location 的「子属性」(sub-properties),这样给定一条边 Santa Lucia
—city→ Santiago
,我们就可以推理出 Santa Lucia
—location→ Santiago
;类似地,我们可以将标签 bus 和 flight 看做属性 connects to 的子属性。这样属性也可以形成一个层级结构。此外,我们还可以定义属性的「领域」(domain)和「范围」(range),用来表示属性所连接的节点所属的类。领域对应是属性所来自的节点,而范围则对应属性所指向的节点。例如,我们定义 connects to 的领域为类 Place
,那么我们就可以得出 Arica
—type→ Place
;定义 city 的范围为类 City
,那么我们就可以得出 Arica
—type→ City
。
一个著名的定义语义模式的标准是用于 RDF 图的 「RDF 模式」(RDF Schema)标准,其允许在 RDF 图中为类和属性定义子类、子属性、领域以及范围,这些定义可以被序列化为一个图。下表说明了这些特征的语义,并在下图中给出了一个具体的例子,这些定义可以被嵌入到数据图之中。此外,通过使用基于 RDF 的「网络本体语言」(OWL),我们还可以进一步地定义更复杂的语义关系(第四节介绍)。
语义模式通常用于定义不完整的数据图,即没有在图中出现的边并不代表真实世界中不存在这种关系,即所谓的「开放世界假设」(OWA)。如图中并不存在边 Viña del Mar
—flight→ Arica
,但我们并不能假定这两个城市间没有飞机通行。与之相对应的是「封闭世界假设」(CWA),其应用于很多经典的数据库系统中。CWA 假定数据图是对世界的完整描述,对于上面的例子,其可以断言两个城市间没有飞机通行。CWA 所带来的一个后果是在数据图中添加边可能会与之前生成的假设相矛盾,而在 OWA 中这种矛盾不会出现,被证明为 false 的观点会始终保持 false。对于上面的例子,直接使用 CWA 显然是不合理的,但是有时候我们可能希望数据图所给出的部分内容(如交通信息)是完整的。这时我们可以使用「局部封闭世界假设」(LCWA),其介于 OWA 和 CWA 之间,假定数据图的部分内容是完整的。
当用图来表示大规模的不完整数据时,开放世界假设是最合适的选择。不过有些时候,我们希望可以确保数据图的特定部分是完整的(注意与 LCWA 的区别,LCWA 不会对图做验证,而只是进行推理)。例如,在图 1 中,我们希望确保所有事件都有至少一个名称、地点、起始时间(用户需要得到的最少信息),同时事件的城市的类型被声明为城市(而不是直接推理)。我们可以通过「验证模式」(validating schema)来定义这些约束,验证数据图是否满足这些约束。总结来看,语义模式用于推理新的图数据,而验证模式则用于验证已有的图数据。
定义一个验证模式的标准方法是使用「形状」(shapes)。形状以数据图中的节点集合为「目标」,并对这些节点指定「约束」(constraint)。作为目标的节点集合可以通过多种方式定义,如一个类的所有实例、一个属性的领域或范围、一个查询的结果、通过特定属性和另一个 shape 相连的节点等。基于目标节点,我们可以定义约束,约束这些节点的给定属性的数量或类型。将一系列相关的 shape 结合在一起,就形成了「形状图」(shapes graph)。
形状图可以被表示为类似 UML 类图。下图给出了一个形状图的示例,其定义了四个相关联形状的约束。每一个形状都表示为一个 box,只有节点满足其中的所有约束才符合该形状。每个形状中定义的约束为特定属性的「数量」(如 [1..*] 表示一个到多个)和「类型」(如 string);另一种约束方式是在形状之间定义以指定属性连接的节点数量。此外,形状还可以继承父形状的约束,通过三角形符号定义,表明子形状中的节点需要满足父形状中的所有约束。
给定一个形状和目标节点,我们可以验证节点是否符合形状。由于形状间约束的存在,往往我们还需要检查其他形状中的节点,这种依赖有时候还是递归的(如 PLACE 形状中存在递归约束)。而在声明形状时,有时我们不能提前知道节点的所有属性集合。类似于开放世界假设,一个「开放形状」(open shape)表示允许节点拥有形状中未指明的属性;相反地「闭合形状」(closed shape)则不允许。此外,在实际应用中,形状通常还支持额外的「布尔特征」,即通过与、或、非将多个形状联合起来以约束节点。不过这有时会导致一些自相矛盾的语义问题,研究者们也针对这个问题提出了一些解决方案(分层、部分分配、稳定模型)。PS:原文在这里给出了一系列的案例,更有助于理解验证模型,感兴趣的童鞋可以自行查看。
虽然验证模式和语义模式的目的不同,但它们可以相互补充。例如,验证模式可以基于语义模式推理的结果进行验证;而语义模式的出现可能会导致验证模式需要调整(属性的数量可能发生变化),这种情况下开放形状可能更加适用。对于 RDF 图来说,目前其有两种形状语言:「Shape Expressions」(ShEx)和 「SHACL」(Shapes Constraint Language),具体的应用在这里不做赘述。
上述两种模式都依赖于领域专家来明确地进行定义和制定约束,而「涌现模式」(emergent schema)可以帮助我们自动发现一个数据图中的潜在结构。
一种常用于定义涌现模式的框架是「商图」(quotient graphs),其将数据图中的节点分割为多个集合(基于某种准则),同时又保护了图的部分结构属性。一般来说,我们会基于节点的类或形状约束来进行划分。以图 1 为例,我们可以简单地基于节点的上下文(其连接的属性)将其分为六个部分:事件、名称、地点、类、日期、城市。将每个部分的节点合并,并保留相应的边后,就可以得到如下图所示的商图。注意边 X
—y→ Z
存在于商图中当且仅当存在
和
以及数据图中存在 x
—y→ z
。
商图的定义不仅取决于节点的分割方式,还取决于边的定义方式。对于上面的商图而言,其只要边对应的集合中存在一个节点能够满足条件,那么这条边就会存在。然而对于节点 EID16
而言,在原始数据图中其并没有起始日期属性。我们可以通过「双拟」(bisimilarity)来为商图定义一种更强的结构保护方式:如果商图中存在边 X
—y→ Z
,那么对于所有的
,必须存在
保证数据图中存在边 x
—y→ z
。基于这种定义,可以画出如下图所示的商图,其将事件部分拆分为了两个节点,反映其不同的边。双拟的一个有趣的属性在于其可以保护前向路径(forward-directed paths)。给定一个没有反转的路径表达式
和两张双拟图,
会在一张图中匹配到一个路径当且仅当其在另一张图中匹配到对应的路径。
本质上看,商图就是将数据图总结为一个更高层次的拓扑结构。在实践中,为了减少存储消耗,商图中有时只保留分割中节点的数量以及(或)分割的顶层标签。除了商图外,还存在着其他形式的涌现模式,如关系表、正式概念分析等。涌现模式可以用于提供对数据图的整体理解,帮助定义语义或验证模式、优化图的索引和查询,指导图的集成等。
在图 1 中,对于一个节点具体指向的内容可能会存在歧义。如对于 Santiago
这个节点,我们并不能单独确定其是指代城市(有三个同名)城市,还是指代一个乐队名。通过结合该节点的属性和整张图的内容,我们可以确定其指向智利的圣地亚哥。这种需要依赖启发式的推理来为节点消除歧义的做法并不可靠。本节我们将主要通过两种方式避免歧义:首先是使用「全局唯一」的标识符,避免在用外部数据扩展知识图谱时的命名冲突;然后是通过添加「外部标识链接」来基于外部源为节点消歧。
假定我们希望比较智利和古巴的旅游景点,并且已经分别创建了两个地区的知识图谱。那么在合并过程中,可能会产生如下图所示的命名冲突问题(naming clash)。为了避免冲突,我们可以创建长效「持续标识符」(PIDs)来独一无二地标识一个实体。PID 的代表案例有:用于论文的 DOI、用于作者的 ORCID 和用于书籍的 ISBN。
在语义网络中,RDF 数据模型推荐使用全局网络标识符来标记节点和边标签。不过 RDF 1.1 并没有使用标记「信息资源」(information resources)位置的「统一资源定位符」(URLs),而是使用了可以用于标识「非信息资源」(non-information resources)的「国际化资源标识符」(IRIs)。这里对几个容易混淆的概念进行说明:
下面将举例说明 URL 和 IRI 用于标识的区别。在 Wiki 数据的 RDF 表示中(一个用于补全维基百科的知识图谱),URL https://www.wikidata.org/wiki/Q2887
指向一个网页,其中提供一些关于特定节点(如圣地亚哥)的相关描述;而 IRI http://www.wikidata.org/entity/Q2887
则指向节点本身(只是命名空间不同,实际上本例中提供的 IRI 会被重定向到上面的 URL)。使用 URL 在某些情况下可能会引发歧义,如下图所示,该 URL 所代表的究竟是其描述的节点还是该网页的创建者?
使用 IRI 则可以避免这些歧义,其指向的为节点本身,如下图所示:
在 Wikidata 的标识符中,使用前缀 http://www.wikidata.org/entity 来标识实体,使用前缀 http://www.wikidata.org/prop/direct/ 来标识关系。这些前缀被称为「命名空间」(namespaces),通常会进行缩写,如 wd:
或 wdt:
。上图中的三元组可以被简写为:wd:Q2887
—wdt:P112→ wd:Q203534
。
如果使用 HTTP IRI 来标识图中的实体,则访问该 IRI 就会得到服务器返回的关于当前实体的描述(以诸如 RDF 等形式)。这种方式也使得 RDF 图可以连接自网络上其他 RDF 所描述的关联实体,从而形成「键连数据」(Linked Data)。虽然 HTTP IRI 可以提供一种灵活且有效的手段来解决网络中的全局标识符的问题,但有时其并不稳定(持久),如 IRI 指向的网站可能会崩掉,或者当前网站的内容会发生改变。为了提升标识符的稳定性,「持久性 URL」(PURL)服务可以提供从中心服务器向特定位置的「重定向」。PURL 可以在不改变标识符的情况下在必要的时候将其指向新的位置(如网站不可用或当前内容改变时)。HTTP IRI 的持久性可以通过使用 PURL 服务定义的命名空间来提升。
在不同的知识图谱中,IRI 对应的命名空间可以在本地自由指定,这就导致可能存在同一个实体对应两个不同的命名空间,例如 chile:Santiago
和 geo:SantiagoDeChile
都指向同一个城市实体。为了确定实体的身份,这里提供两种处理方式:第一种方式是将实体和图谱中的「特定标识信息」关联起来,比如城市的地理坐标,邮政编码,建立时间等,每一个额外添加的信息都可以消除歧义,帮助在外部源中匹配类似的实体。第二种方式是使用「标识链接」(identity links)来声明一个本地的实体与另一个外部源中的实体具有相同的身份。这一概念的一个实例可以在 OWL 标准中找到,其定义了属性 owl:sameAs 来关联共指实体。例如在 RDF 图中,我们可以声明 chile:Santiago
—owl:sameAs→ geo:SantiagoDeChile
,这样我们就可以认为两个节点指向同一个实体,从而将其数据进行合并。关于数据的合并和标识链接的计算将在之后讨论。
对于图 1 中的左侧的两个日期,直接为其分配 IRI 标识符似乎不太恰当。不同于一般实体,日期数据可以被机器所识别,通过适当的软件,我们可以将其对应的值进行排序,或是进行从中抽取年份等操作。大部分实际的图数据模型都允许定义包含「数据类型值」(datatype values)的节点。在 RDF 中,采用 「XML Schema Datatypes」(XSD)来定义数据类型节点,其形式为
,其中
是一个字符串,例如 2020-03-29T20:00:00
,
则是一个 IRI,用于定义数据类型,例如 xsd:time
。该节点最终被表示为 2020-03-29T20:00:00"^^xsd:dateTime
。RDF 中的数据类型节点被称为「字面量」(literals),其不允许拥有向外的边。RDF 中常用的数据类型包括 xsd:string
、 xsd:integer
、xsd:decimal
、 xsd:boolean
等,如果数据类型没有指定,则默认为 xsd:string
。基于 RDF 构建的应用可以识别出这些数据类型,将其解析为数据类型对象,根据其标准定义进行一系列的操作。而在属性图中,Neo4j 也定义了一系列内部数据类型,包括数字、字符串、布尔值等。
虽然全局化的标识符有时候以人类可以理解的形式展示,如 chile:Santiago
,但实际上以人类无法理解的形式来定义标识符可以提升其稳定性,如 wd:Q2887
,其不会受特定的语言影响。而为了提升这种标识符的可理解性,我们可以为其添加标签,如 wd:Q2887
—rdfs:label→ "Santiago"
,来帮助人们理解标识符的实际含义。我们也可以进一步添加别名或评论来描述该实体,如 rdfs:comment 和 skos:altLabel。在 RDF 中,还可以指定标签所对应的语言,如 chile:City
—rdfs:label→ "City"@en
。包含人类可理解的标签、别名与评论等的知识图谱有时也被称为「词汇化知识图谱」(lexicalised knowledge graphs)。
在对不完整信息进行建模时,有时我们可能会遇到这样的情况:图中一定存在一个特定的节点,其余其他节点有着特定的关系,但是在建模中我们并不了解该节点的具体信息。例如我们有两个在同一地点举办的活动 chile:EID42
和 chile:EID43
,其举办地点还没有被声明。一种做法是直接忽略地点相关的边,这样会丢失举办地点的信息;另一种做法则是为这个地点创建一个新的 IRI,但是我们无法将其与已知的地点进行区分,因此我们需要一种更好的方法来表明这种存在性关系。
一些图模型通过「存在性节点」来表达这种关系。存在性节点通过空白圆圈来表示,如上图所示。这些边表明对于两个活动,存在一个共同的地点,但是又没有指明其具体信息。在 RDF 中,存在性节点以空白节点的形式表达,通常 用于建模图中的复杂元素,例如 「RDF 列表」(RDF lists)。下图给出了一个 RDF 列表的案例,其将空白节点编码为一种链表结构。虽然存在性节点比较方便,但其可能会复杂化关于图的计算,因此研究者们也提出了一些新的替代方法,例如将存在性节点 Skolem 化为规范标签。
实际上,图 1 中所包含的事实可以理解为在特定的「上下文」(context)中成立,如航班开始运行的时间,事件发生的地点,活动命名的起源等。这些上下文形式各异,可以进行组合,用于声明「事实成立的范围」(scope of truth),即在何种情况下数据为真。图 1 中的上下文并没有明确地表示出来,而有时明确地表示上下文可以帮助我们从不同的角度来理解数据。此外,图数据的上下文可以从不同的级别进行表示,如针对单个节点、单条边或是边的集合等。本节将介绍多种上下文的表示形式。
第一种表示上下文的方法是将其作为图中的「数据」(与其他数据相同)。例如,对于图 1 中的活动 EID15
,我们可以将其视作一种时间上下文的形式,其起始时间定义了部分关系(边)成立的时间范围;我们也可以讲边表示的关系转化为节点,然后为其添加额外的上下文关系。在上面的例子中,表示上下文的方式不具有一般性,实际上研究者们已经提出了许多规范来以更标准的方式将上下文表示为数据。一个例子是 RDF 图中的「时间本体」(Time Ontology),其定义了如何以可互操作的方式描述时间实体、时间间隔、时刻以及它们之间的关系;另一个例子是 「PROV 数据模型」(PROV Data Model),其指定了如何在 RDF 图中描述「出处」(provenance)。
在上一种方法中 ,对于边的上下文我们只能够先将其转化为节点,再添加上下文关系。实化(reification)可以直接表示边的上下文,通过定义关于「边的边」(edges about edges)的方式。下图给出了三种主要的实化形式,可以用于为有向标记图中的边定义时间上下文(以定义边 Santiago
—flight→ Arica
自 1956 年开始为例)。我们使用
来定义一个表示边的任意标识符,以此连接上下文信息。「RDF 实化」定义一个新节点 e
来表示边,并将其通过特定的边连接到源节点、目标节点和边标签上。而 「n-ary 关系」则直接通过边标签连接自源节点;「单例属性」则将 e 作为一个边标签,连接至表明其原始边标签的节点(通过 singleton)。
除了使用实化,我们也可以使用「高元表示」(higher-arity representation)来建模上下文。下图给出了三种时间上下文的表示方法。首先,我们可以使用一个「命名图」来包含目标边,然后针对图的名称定义上下文;我们也可以使用「属性图」来将上下文定义为边的属性;我们还可以使用 「RDF*」,一种 RDF 的扩展,允许将边定义为节点。在这三种方法中,最灵活的是命名图表示,我们可以将多条边纳入到命名图中以一次性对其添加上下文;最不灵活的则是 「RDF*」,由于缺少边 id,其不允许将不同的上下文组合赋予同一条边。
到目前为止我们已经介绍了几种在图中表示上下文的方法,但还没有涉及如何关于上下文的自动推理技术。有时候我们可能需要从给定的上下文中提取出相关信息,直接遍历查询所有对应的上下文显然不是一种好方法。我们可以使用「注解」(annototations)来为一个上下文域提供数学化的定义以及该领域内可自动执行的关键操作。
部分注解形式是针对特定的上下文领域的,如 「Temporal RDF」 和 「Fuzzy RDF」,前者允许为边标注时间间隔,后者则允许为边标注一个真实度(概率)。而另一些注解形式则是领域无关的,如 「Annotated RDF」,其可以将各种形式的上下文表示为 「semi-rings」——由领域值(如时间间隔、真实度)组成的代数结构,同时提供两种组合领域值的操作符:「meet」 和 「join」。下图给出了一个例子,其中
通过一个简化的时间域的值进行了注解,数字代表一年中的各个日期,为了简化使用了间隔标注。查询
希望查询从 Santiago 飞往有活动举办城市的航班,该查询会检查并返回一个反映每个答案的时间合法性的注解。我们首先会使用 meet 操作符来计算每一个查询结果中两条边的时间范围对应的注解,这里会使用日期集合的「交集」;然后针对所有非空的注解集合,使用 join 操作符来计算注解集合的「并集」,作为最终结果返回。
除了上述方法外,还有一些其他的用于上下文建模和图例的框架。一个比较著名的例子就是「上下文知识仓库」(contextual knowledge repositories),其允许为单个图(子图)分配其独立的上下文。不同于命名图,这里的上下文会明确指定维度(一维或多维),每一张图都必须在每个维度上设定一个值(即所有图的上下文是相同维度的),每个维度又进一步地定义了内部值的排序方式。这种方法可以帮助选择与组合不同粒度级别上下文中的有效子图。另一个例子是「上下文 OLAP」(在线分析处理)框架,其由一个多维数据立方构成,其中的单个细胞包含知识图谱。框架支持诸如 「slice-and-dice」(选择指定维度的知识)、「roll-up」(将知识聚合到更高的层级)等操作。