知识图谱学习笔记——(三)知识图谱的存储与查询
一、知识学习
声明:知识学习中本文主体按照浙江大学陈华钧教授的《知识图谱》公开课讲义进行介绍,并个别地方加入了自己的注释和思考,希望大家尊重陈华钧教授的知识产权,在使用时加上出处。感谢陈华钧教授。
(一)B站 《浙大知识图谱完整版》——3
学识时间:2023年4月18日17:05:32
3、知识图谱的存储与查询
3.1基于关系型数据库的知识图谱存储
3.1.1 知识图谱的存储方式
(1)知识图谱的存储需要综合考虑知识结构、 图的特点、 索引和查询优化等问题。
(2)典型的知识图谱存储引擎分为基于关系数据库的存储和基于原生图的存储。
(3)图数据库存储并非必须, 例如Wikidata项目后端是MySQL实现的。
图结构模型
属性图和RDF图模型都是有向标记图: Directed Labeled Graph
3.1.2 图上的查询语言
SPARQL语言:
SPARQL语法参考
最简单的存储: Triple Store
Property Tables: 属性表存储
- 属性表存储也称为垂直仍然基于传统关系数据库实现, 典型的如Jena [Wilkinson et al.,2003] ,FlexTable [Wang et al., 2010] , DB2-RDF [Bornea et al., 2013]等实现
- 基本思想是以实体类型为中心, 把属于同一个实体类型的属性组织为一个表, 即属性表进行存储。
– 优点: Join减少了, 本质上接近于关系数据库, 可重用RDBMS功能
– 缺点: 很多空值, 对Subject聚类比较复杂、 不易处理多值属性。
Binary Tables: 二元表
- 二元表也称为垂直划分表, 也是基于关系数据库实现的三元组存储方式,基本思想是对三元组按属性分组, 为每个属性在关系数据库中建立一个包含( subject、 Object) 两列的表。
- 由于一个知识图谱中属性数量是有限的, 表的总体数量是可控的。
– 优点是没有空值、 也不需要聚类、 对于Subject-Subject-Join操作性能好。
– 缺点是Insert性能损耗高、 并且Subject-Object Join性能差。
Exhaustive Indexing: 全索引结构
- 性能最好的存储方式是基于全索引结构的存储, 典型的实现包括RDF-3X, Hexastore等。 这种方法也仅维护一张包含(Subject, Predicate,Object) 的三列表, 但增加了多个方面的优化手段。
- 第一个优化手段是建立Mapping Table, 即将所有的字符串首先映射到唯一的数字ID, 这一将大大压缩存储空间
- 进一步建立六种索引: SPO, SOP, PSO, POS, OPS, OSP, 即分别建立SubjectPredicate-Object; Subject-Object-Predicate; Predicate-Subject-Object等六个方面的全索引, 显然多种形式的索引覆盖了多个维度的图查询需求。
- 同时三元组基于字符串排序, 并利用clustered B+ tree树来组织索引以进一步优化索引检索的效率
小结:
3.2基于原生图数据库的知识图谱存储
3.2.1关系型数据库的局限性
(1) 关系模型不善处理“关系”
- 关系模型将语义关联关系隐藏在外键结构中, 无显示表达,并带来关联查询与计算的复杂性。
- 数据来源多样性带来大量离群数据( Outlier Data),导致数据集的宏观结构愈发复杂和不规整, 对于包含大量离群数据的场景, 关系模型将造成大量表连接、 稀疏行和非空处理。
- 互联网的开放世界假设要求数据模型满足高动态和去中心化的扩增数据的能力, 关系模型对表结构的范式要求限制了Schema层的动态性
关系模型背离了用接近自然语言的方式来描述客观世界的原则, 这使得概念化、 高度关联的世界模型与数据的物理存储之间出现了失配
SELECT p1.Person FROM Person p1 JOIN PersonFriend ON PersonFriend.FriendID = p1.ID JOIN Person p2 ON PersonFriend.PersonID = p2.ID WHERE p2 .Person = 'Bob'
- 处理Reflexive relationship的自反查询带来底层数据库的更多计算, 从图的角度, 只需声明friend关系是自反关系即可支持反向查询。
who is friends with Bob?
SELECT p1.Person FROM Person p1 JOIN PersonFriend ON PersonFriend,PersonID = p1.ID JOIN Person p2 ON PersonFriend.FriendID = p2.ID WHERE p2.Person = 'Bob'
编者注:
依照图表关系,如果通过"person"找此人的Friends很方便,也很快捷,但是如果说列出朋友是Bob的人,那么就要遍历朋友表,一个一个的核对FriendID是否为Bob的ID。这样,如果此表非常大,那么传统的结构化表格的查询就会非常的浪费。
3. 处理Chain relationship 的多跳查询带来更加复杂的Join计算 ,有些数据库如Oracle提供了Syntax Suger如Connect By”, 但没有降低底层的计算复杂度.
SELECT p1.Person AS PERSON,p2.Person AS FRIEND_OF_FRIEND FROM PersonFriend pfl JOIN Person p1 ON pfl.PersonID = p1.ID JOIN PersonFriend pf2 ON pf2.PersonID = pfl.FriendID JOIN Person p2 ON pf2.FriendID = p2.ID WHERE pl.Person = 'Alice' AND pf2.FriendID pl.ID
(2) 处理关联查询
举例一: 找出两个银行账户交易记录的最短路径
举例二: 找出两个社交账户消息发送的最短路径
1,000,000 people, each with approximately 50 friends, query to a maximum depth of five
(3)知识图谱需要更加丰富的关系语义表达与关联推理能力
- 在需要更加深入的研究数据之间的关系时, 需要更加丰富的关系语义的表达能力,除了前述Reflesive和多跳关系、 还包括传递关系Transitive、对称关系( 非对称关系)Symmetric、反关系( Inverse) 、函数关系( Functional)。
- 除了关联查询能力, 深层次的关系建模还将提供关联推理的能力, 属性图数据库如Neo4J提供了由于关系模型的关联查询能力, AllegroGraph等RDF图数据库提供了更多的关联推理能力。
(4)NoSQL数据库也不善于处理关联关系
- 关系在NoSQL数据库中也不是First-Class Citizen, 在处理数据关联也需要使用类似于外键的Foreign Aggregates。
- Foreign Aggregates不能处理自反关系 , 例如,查询“ who is friends with Bob?” 时, 需要暴力计算, 即扫描所有实体数据集 。
- Foreign Aggregates也不负责维护Link的有效性, 在处理多跳关系时效率也很低下。
3.2.2 图数据库
Relations are first-class citizens
(1)原生图数据库
利用图的结构特征建索引
(2)图数据建模的好处
- 自然表达: 图是十分自然的描述事物关系的方式 , 更加接近于人脑对客观事物的记忆方式。
- 易于扩展: 图模型更加易于适应变化 , 例如在图中, 临时希望获取历史订单, 只需新增边即可。
- 复杂关联表达: 图模型易于表达复杂关联逻辑的查询 , 例如在推荐系统中, 希望表达复杂的推荐逻辑, 例如: “ all the flavors of icecream liked by people who enjoy espresso but dislike Brussels sprouts, and who live in a particular neighborhood.”
- 多跳优化: 在处理多跳查询 上, 图模型有性能优势。
(3)Neo4J
- 属性图是图数据库Neo4J实现的图结构表示模型 , 在工业界有广泛应用。
- 在属性图的术语中, 属性图是由 顶点( Vertex) , 边( Edge) , 标签( Label) , 关系类型还有属性( Property) 组成的有向图 。
- 在属性图中, 节点和关系是最重要的实体 。 节点上包含属性, 属性可以以任何键值形式存在。
(4)图查询语言: Cypher
Cypher of Neo4J:
MATCH (a:Person {name:'Jim'})-[:KNOWS]->(b)-[:KNOWS]->(c), (a)-[:KNOWS]->(c) RETURN b, c
SPARQL of W3C:
Select ?a,?b,?c where { ?a :KNOWS ?b.?b :KNOWS ?c. ?a :KNOWS ?c. ?a ISA :Person. ?a :name = "Jim". }
Gremlin of Apache TinkerPop:
g.V().has(“name","Jim"). out(“:KNOWS"). out(“:KNOWS”). values("name")
(5)跨领域图建模与查询
- 利用图谱将不同领域的数据进行关联
- 要求模型能按需扩展
- 查询语句能表示跨多个领域的关联逻辑
CREATE (shakespeare:Author {firstname:'William', lastname:'Shakespeare'}), (juliusCaesar:Play {title:'Julius Caesar'}), (shakespeare)-[:WROTE_PLAY {year:1599}]->(juliusCaesar), (theTempest:Play {title:'The Tempest'}), (shakespeare)-[:WROTE_PLAY {year:1610}]->(theTempest), (rsc:Company {name:'RSC'}), (production1:Production {name:'Julius Caesar'}), (rsc)-[:PRODUCED]->(production1), (production1)-[:PRODUCTION_OF]->(juliusCaesar), (performance1:Performance {date:20120729}), (performance1)-[:PERFORMANCE_OF]->(production1), (production2:Production {name:'The Tempest'}), (rsc)-[:PRODUCED]->(production2), (production2)-[:PRODUCTION_OF]->(theTempest), (performance2:Performance {date:20061121}), (performance2)-[:PERFORMANCE_OF]->(production2), (performance3:Performance {date:20120730}), (performance3)-[:PERFORMANCE_OF]->(production1), (billy:User {name:'Billy'}), (review:Review {rating:5, review:'This was awesome!'}), (billy)-[:WROTE_REVIEW]->(review), (review)-[:RATED]->(performance1), (theatreRoyal:Venue {name:'Theatre Royal'}), (performance1)-[:VENUE]->(theatreRoyal), (performance2)-[:VENUE]->(theatreRoyal), (performance3)-[:VENUE]->(theatreRoyal), (greyStreet:Street {name:'Grey Street'}), (theatreRoyal)-[:STREET]->(greyStreet), (newcastle:City {name:'Newcastle'}), (greyStreet)-[:CITY]->(newcastle), (tyneAndWear:County {name:'Tyne and Wear'}), (newcastle)-[:COUNTY]->(tyneAndWear), (england:Country {name:'England'}), (tyneAndWear)-[:COUNTRY]->(england), (stratford:City {name:'Stratford upon Avon'}), (stratford)-[:COUNTRY]->(england), (rsc)-[:BASED_IN]->(stratford), (shakespeare)-[:BORN_IN]->stratford
literary domain
theatrical domain
geospatial domain
(6)Cypher图查询举例
Finds all the Shakespeare performances at Newcastle’s Theatre Royal
MATCH (theater:Venue {name:'Theatre Royal'}), (newcastle:City {name:'Newcastle'}), (bard:Author {lastname:'Shakespeare'}), (newcastle)(play) 1608 RETURN DISTINCT play.title AS play
Identify potentially suspect behavior:retrieve all the emails that Bob has sent where he’s CC’d one of his own aliases.
MATCH (bob:User {username:'Bob'})-[:SENT]->(email)-[:CC]->(alias), (alias)-[:ALIAS_OF]->(bob) RETURN email.id
3.2.3 常见的图数据库列表
小结:
3.3 原生图数据库实现原理浅析
3.3.1 原生图数据库的实现原理
(1) 免索引邻接
- 原生图是指采用免索引邻接( Index-free adjacency) 构建的图数据库引擎, 如:AllegroGraph, Neo4j等。
- 采用免索引邻接的数据库为每一个节点维护了一组指向其相邻节点的引用, 这组引用本质上可以看做是相邻节点的微索引( Micro Index) 。
- 这种微索引比起全局索引在处理图遍历查询时更廉价, 其查询复杂度与数据集整体大小无关,仅正比于相邻子图的大小。
(2) 常见Table Join的计算复杂度
Nested Join O(M*N):
FOR erow IN (select * from employees where X=Y) LOOP FOR drow IN (select * from departments where erow is matched) LOOP output values from erow and drow END LOOP END LOOP
Hash Join O(M + N):
FOR small table_row IN (SELECT * FROM small_table) LOOP slot_number := HASH(small_table_row.join_key); INSERT_HASH_TABLE(slot_number,small_table_row); END LOOP;
FOR large_table_row IN (SELECT * FROM large_table) LOOP slot_number := HASH(large_table_row.join_key); small_table_row = LOOKUP_HASH_TABLE(slot_number,large_table_row.join_key); IF small table_row FOUND THEN output small_table_row + large_table_row; END IF; END LOOP;
Merge Join O(NLog(N) + MLog(M)):
READ data_set_1 SORT BY JOIN KEY TO temp_ds1 READ data set_2 SORT BY JOIN KEY TO temp ds2 READ ds1_row FROM temp_ds1 READ ds2_row FROM temp_ds2 WHILE NOT eof ON temp_ds1,temp_ds2 LOOP IF ( temp_ds1.key = temp_ds2.key ) OUTPUT JOIN ds1_row,ds2_row ELSIF ( temp_ds1.key temp_ds2.key ) READ ds2_row FROM temp_ds2 END LOOP
(3)Index-free adjacency的计算复杂度
- 而对于 Index-free adjacency, 关系是 直接基于某个节点的相邻节点获取的(tail to head, or head to tail),例如, 为了查询“ who is friends with A l i c e ” , 我 们 只 需 要 检 索 A l i c e 的 所 有 incoming FRIEND 关系即可, 这个复杂度仅与节点的邻居个数有关, 而与整个数据集的大小是无关的。
3.3.2 原生图数据库的物理存储实现
(1)节点存储文件:
- 节点存储于独立的“ 节点存储文件” , 每个节点的存储空间固定,如14字节, 便于直接通过ID编号计算获得访问地址, 基于这种格式,节点查询成本为O(1) , 而非O(N);
- 每个节点首字节标明是否inUse, 接下来四个字节存储该节点的第一个关系边的ID, 再接下来四个字节存储该节点的第一个属性ID,再接下来4个字节存储该节点的第一个Label ID;
- 节点的属性数据( 如姓名、 年龄等) 是分开存储的, 节点只存储其第一个属性的ID , 这样的设计是为了保证节点遍历的高效性。
(2)关系存储文件
- 关系边存储于独立的“ 关系存储文件” , 每个关系边的存储空间固定, 如34字节,和节点一样, 这种设计 便于直接通过ID编号计算获得关系边的访问地址 。
- 每个节点首字节标明是否inUse, 接下来四个字节存储该关系边的头节点ID, 再接下来四个字节存储该关系边的尾节点ID, 再接下来4个字节存储关系边类型ID, 再下面存储头节点和尾节点的上一个关系边ID, 以及头尾节点的下一个关系边ID。
3.3.3 图遍历的查询的物理实现
主要优化的点:
1.节点的查找, 关系的查找
2. 从节点到关系, 从关系到节点
3. 从关系到关系
4. 从节点到属性, 从关系到属性
5. 从关系到关系类型.
3.3.4 属性数据的存储处理
(1)内联与动态存储
- 图数据库中存在大量属性, 这些 属性的检索与图遍历的计算是分开的, 这是为了让节点之间的图遍历能不受大量属性数据的影响 。
- 节点和关系的存储记录都 包含指向它们的第一个属性ID的指针, 属性记录也是固定大小, 便于之间通过ID计算获得存储位置 。
- 每个属性记录包含多个属性块, 以及属性链中下一个属性的ID 。
- 每个属性记录包含属性类型以及属性索引文件 , 属性索引文件存储属性名称。
- 对于每一个属性值, 记录包含一个指向动态存储记录的指针( 大属性值) 或内联值( 小属性值)
3.3.5 RDF图模型和属性图模型的比较
参见《知识图谱数据管理研究综述》 王鑫等
3.3.6 知识图谱查询语言的比较
参见《知识图谱数据管理研究综述》 王鑫等
3.3.7 常见知识图谱数据库管理系统比较
参见《知识图谱数据管理研究综述》 王鑫等
总结:
(1)知识图谱存储的选择
- 知识图谱存储方式的选择需要 综合考虑性能、 动态扩展、 实施成本等多方面综合因素。
- 区分原生图存储和非原生图存储: 原生图存储在复杂关联查询和图计算方面有性能优势, 非原生图存储兼容已有工具集通常学习和协调成本会低。
- 区分RDF图存储和属性图存储: RDF存储一般支持推理, 属性图存储通常具有更好的图分析性能优势。
- 在大规模处理情况下, 需要考虑与底层大数据存储引擎和上层图计算引擎集成需求。
(2)关于图模型与图数据库
- 图模型是更加接近于人脑认知和自然语言的数据模型, 图数据库是处理复杂的、半结构化、 多维度的、 紧密关联数据的最好技术。 我们鼓励在知识图谱项目中采用和实践图数据库。
- 图数据库有它弱处, 假如你的应用场景不包含大量的关联查询, 对于简单查询,传统关系模型和NoSQL数据库目前在性能方面更加有优势。
- RDF作为一种知识图谱表示框架的参考标准, 向上对接OWL等更丰富的语义表示和推理能力, 向下对接简化后的属性图模型以及图计算引擎, 是最值得重视的知识图谱表示框架。
------------------本部分最新更新时间:2023年4月24日10:58:20
- 而对于 Index-free adjacency, 关系是 直接基于某个节点的相邻节点获取的(tail to head, or head to tail),例如, 为了查询“ who is friends with A l i c e ” , 我 们 只 需 要 检 索 A l i c e 的 所 有 incoming FRIEND 关系即可, 这个复杂度仅与节点的邻居个数有关, 而与整个数据集的大小是无关的。
- 处理Reflexive relationship的自反查询带来底层数据库的更多计算, 从图的角度, 只需声明friend关系是自反关系即可支持反向查询。