图形数据库是通过使用图形数据建模来存储和处理数据的NoSQL 数据库系统。
来自451 集团的Matt Aslett 指出图形数据库已慢慢从通用NOSQL 中脱离出来,自己独成一类。在过去的12 到18 个月里,图空间出现了一个大的转换,所有事物图的分类都增加了。
通过使用图形数据库进行的数据建模尝试遵循不同的样式,既不同于关系数据库中常用的建模,也不同于其他NoSQL 数据库,如文档数据库、关键值数据存储或Column Family 数据库中的建模。图形数据建模能用于创建丰富且高度相连的数据来代表现实生活中的实例和应用。
InfoQ 与来自 Neo Technologies 团队的 Jim Webber 和 Ian Robinson(同时也是 Graph Databases 一书联合作者)讨论了使用图形数据库管理和分析数据时的数据建模尝试和最佳实践。
InfoQ:什么类型数据不适合存储于关系数据库,却是使用图形数据库的不二对象?
Jim & Ian:这个问题的答案非常直接:任何可即刻互联的东西。因为编码和模式设计比较复杂,或更甚者,是因为联合炸弹问题 [ http://blog.neo4j.org/2013/01/demining-join-bomb-with-graph-queries.html ] 所固有的关于关系建模的任意实际应用。
根据你所要关联的等级,即使是大型数据集,关系型数据库也都是特别棒的工具。在我们能见到的所有关系型数据使用案例中,总是存在有联合。在极端情况下,当一个 ORM(对象关系映射)已编写并隐藏了表现特别差的 SQL 时,会有较多的任意联合。
联合的问题在于你永远不知道会生成什么样的中间数据集,这意味着你永远不确定内存使用情况或带有联合的查询所需的等待时间。如果是多个联合叠加在一起的话,那其查询非常有可能执行起来特别慢,并消耗大量(稀缺)资源。
InfoQ:比起关系型数据库,使用图形数据库有哪些优势呢?
Jim & Ian:就行业而言,我们在迫使将各种数据存入关系数据库这方面已颇具创意(而且对其所带来的后果也已经颇为冷静了!)。关系数据库确实是计算机系统开发的金钥匙,我们中的很多人都不愿意从工具链中放弃 RDBMS,哪怕有更好的选择,也会因为熟悉度而放弃。
尽管如此,依然有两个潜在因素驱动着从关系数据库到 Neo4j 的转换。首先你要观察你所在的领域是否是连接的数据结构(比如:社交网络、医疗保健、权限管理、实时物流和各种推荐工具等),然后你会意识到在这些领域使用 Neo4j 的话,将使存储和查询变得简单而有趣,不像使用关系型数据库那样困难和令人不悦。尤其当案例是由了解这方面的技术人员(至少有一定程度的理解)驱动的,他们明白所要处理的图形问题,且已准备好使用 Neo4j 来快速且巧妙地解决图形问题。他们当然不想陷于稀疏表和超级联接表的泥沼中。
另一个驱动就是性能了。尽管关系型数据库中的联和给使用它们的系统带来的痛苦已减轻。可能你的第一个联和是性能良好的,如果幸运的话,你的第二个联和也是。但是随着数据集大小不断增大,对联和的自信也会随着查询时间的增加而逐渐消耗。为了试图解决一些连接或路径问题,联和密集型模式应运而生,但它并不适用于模拟路径操作。而 Neo4j 在路径操作这方面就没有这样的问题:作为查询的一部分,查询时间随着所需挖掘的数据量线性增长,而不是随着数据集的总体大小增长(数据量可能无穷大)。因此如果你已经感到联和所带来的痛苦,那这又是另外一个提示:Neo4j 图形数据库将是关系型数据库中复杂数据模型更好的解决方案。
InfoQ:相对于其他 NoSQL 数据库,使用图形数据库有哪些优势?
Jim & Ian:我们觉得 Fowler 和 Sadalage 在他们的《NoSQL Distilled》一书中已经回答了这个问题。他们指出:在这四种 NoSQL 存储中(图形,键值,列和文档),其中键值、列和文档这三种可以定义为“聚集存储”。聚集存储特别适用于当存储和检索模式是对称的。比如:根据键值存储和检索购物篮或客户文件等。
但是如果你想分析整个聚集体中的数据的话,就比较棘手了。比如:如何查询不同客户群体所喜欢的流行产品?如何做到实时,例如此时你正在为系统中的一个客户进行服务呢?
尽管这些活动都是基本领域术语,但在聚集存储中解决起来却相当困难。其结果就是,使用这些存储的开发人用被迫通过计算,而非查询去获取答案。这也是为什么聚集存储这么热衷于映射简化风格的交互。
Neo4j 的数据模型远远比聚集存储或关系型数据库更具表现力。重要的是,这一模型强调了将联和作为第一级概念。图形中客户,产品,人口统计和趋势之间的关联才是这些实时分析问题所需的答案。Neo4j 通过遍历(查询)图表,而非潜在的映射简化计算为我们提供答案。
图表中,我们在查询时将任意维度信息(不同关系类型)结合在一起以便捷且快速地回答复杂问题。在非原生图形数据库中(其中包括其它类型的 NoSQL 存储),遍历并非是真正的遍历。其发生在应用层,必须在代码中编写及维护。如果它们还通过网络,那与原生图形数据库对比的话,更要慢上几个数量级。而 Neo4j 则由高度优化的图形查询引擎解决了此问题。
InfoQ:你能描述下使用图形数据库的典型数据建模流程吗?
Jim & Ian:Neo4j 所用的图模型叫做“标记属性图”,该实用模型避开了图论中一些较深奥的数学部分,以便于理解和设计。
标记属性图由通过关系联接的节点(通常用来代表实体)组成。节点可以有一个或多个标记,用于标示其每个节点在数据集中所扮演的角色。每个关系都有相应的名字和方向,它们一起为由关系关联的节点提供具体上下文。节点和关系都可以包含一个或多个属性。我们通常使用节点属性来代表实体属性,通过关系属性定义指定关系的权重,强度和质量。
这些基本图信息为我们提供了简单、紧凑以及便于推理的建模套件。比如,通过使用 Neo4j 的 Cypher 查询语句,我们可以简单地描述“Alice loves cookies 爱丽丝喜欢饼干(Alice loves cookies)”这一语句:
(:Person {name: ‘Alice’})-[:LOVES]->(:Food {type: ‘Cookie’})
该路径表达式说明了,其中的节点代表了一个名叫爱丽丝(Alice)的人(Person)喜欢一个特定的食品类型(food type):饼干(cookies)。可以很容易想到:如果多次重复该表达式,我们将得到大量关于人们及其对食物的偏好(或过敏,或厌恶等)的有趣图形。
数据建模包含使用属性图中的基本元素(节点,关系,属性和标签)构建基于应用程序的图形数据模型,该模型允许我们轻松地表达任意一个关于该应用程序领域的问题。
当使用 Neo4j 构建应用程序时,我们通常采用多步骤流程,开始于对所要解决问题的描述,然后以我们想要执行的查询结束,该查询是针对基于应用程序的图形数据模型。该流程可以以迭代和增量方式应用于对数据模型的构建,该模型与应用其余部分的迭代和增量开发可以同步发展。
步骤 1. 描述客户或终端用户的目标,该目标将驱动我们的模型
我们想要解决的问题是什么?在提供对模型想要解决的问题简洁且自然的描述上,我们发现敏捷用户故事特别适用。其实任何对需求的描述都可做为我们建模的基础。
步骤 2. 重写这些目标,将其转换成我们系统所需回答的问题
敏捷用户故事描述了应用程序试图要解决的问题。以应用领域达到目标所需回答的问题形式重写每个目标,从而对定义如何在应用程序上实现,我们又前进了一步。尽管我们依然处于对解决方案的非正式描述阶段,但我们所描述的基于领域的问题已经为下一步流程提供了丰富的数据。
步骤 3. 定义实体及其在这些问题中呈现出来的相互关系
语言本身就具有逻辑关系结构。通过密切结合用于描述我们领域和我们想要回答的问题的语言,我们可以轻易地定义图形结构,而该结构代表了以节点,关系,属性和标签为元素的逻辑结构。常用名词,比如:“人(person)”或“公司(company)”,更多地倾向作为某事物的组或类,或该事物所执行的角色:这些常用名词都是候选标签名。而那些提示事物是如何联接的带有宾语的动词则成为候选关系名。而类似人名或公司名这样的专用名词则往往指代事物具体实例,我们将其建模为节点和节点属性。
步骤 4. 将这些实体和关系翻译成 Cypher 路径表达式
在这一步,我们正式将这些候选节点,关系,属性和标签的描述转换为 Cypher 路径表达式。这些路径表达式构成了应用程序图形数据模型的基础,而该模型描述了路径及其结构的同时,我们也期望在其中找到致力于解决我们应用程序需要的图形。
步骤 5. 使用类似于领域建模的路径表达式以及图形模式表达我们想从领域提取的问题。
现在我们已经从我们领域想要咨询的问题中提取了基本图形结构,是时候将这些问题以图形查询形式表述出来,而这些查询也应围绕着相同的结构。大部分 Cypher 查询的核心是匹配条款(MATCH clause),它包含一个或多个路径表达式描述了我们想在数据集中查找或创建的那类图形结构。如果我们已经努力通过领域的自然语言描述并指导基本图形结构,我们将发现很多针对数据要执行的查询会使用类似用于架构图形的路径表达式。关键点在于其生成的结构是我们想从领域咨询的问题的表达式:该模型与针对模型所执行的查询具有相同形态。
InfoQ:应该什么时候建模,在数据库还是应用层上建模?
Jim & Ian: 从我们对建模流程的描述,可以看出大部分建模发生在数据库中。标记的属性图形基本元素允许我们创建非常具有表现力和具有丰富语义的图形模型,该步骤只有很少或几乎没有任何复杂性,例如没有外键或联和表影响我们的建模意图。
尽管如此,领域中依然有一些特性最好执行于应用程序中。Neo4j 并不存储行为,也没有类似领域驱动设计(Domain-Driven Design)中像聚合(aggregate)这样的严格概念。聚合是由根实体限制的复合结构,该实体控制了整个生命周期的访问和管理。
其实图形没有聚集边界(超出由节点记录状结构叠加的边界)这一概念并非就是缺点。毕竟图形模型强调的是互联性。一些最具价值的发现可以从数据中生成,而这些数据要求我们考虑那些在其它上下文被认作是离散实体之间的关联。我们对遵循或定义新组合和那些连接了在初始领域概念中未出现的结构的新边界突破点的能力,决定了很多预测分析和辩证分析技巧。Cypher 丰富的路径表达语法,以及对可变长度路径和可选子图结构的支持,能有效地允许我们在查询时识别并实现新复合结构。
InfoQ:什么是“超边(Hyperedges)”?针对它们,应该如何建模?
Jim & Ian:超边来自另外一个叫做“超图(hypergraphs)”的图形模型。超边是特殊类型的关系,它连接了两个或两个以上节点。举个例子:你在 Facebook 上‘赞’了某个东西,然后你的朋友‘赞’了你的赞。尽管很多理论家和其它图形数据库中非常拥护超边,但它并不是 Neo4j 的主要成分。以我们经验来看,它们仅在相对较小范围的案例中适用。而其小范围适用性也往往被附加复杂性及其智力成本抵消掉了。
当然在 Neo4j 中,我们可以通过往图形中添加另一个节点(中间节点)为超边建模。比如,我们可以设计最初那个赞 (alice)-[:LIKES]-(post) 如下:(alice)-[:CREATED]->(like)-[:FOR]->(post),就这样我们有了(赞)这个节点。接下来要赞这个赞就非常容易了:(bob)-[:LIKES]->(like)。这不但在需要时带来了与超边等同的功能,也在不需要时(大部分时候)避免了这些复杂性。
InfoQ:为图形数据建模时,什么实践是最好的?
Jim Webber & Ian Robinson:
- 从用例中提取关系名 这么做可以使在模型中创建的路径简易地与你想在数据中查找的模型相匹配。这保证了从用例提取的查询只看到这些路径,从而消除了与所需考虑的图形范围无关的部分。随着新案例的出现,可以根据需求重新使用现有关系或新建一个。
- 使用中间节点连接多方面 中间节点可以作为领域相关的中心,连接了任意数量的实体。比如:工作节点,它连接了一个人,一个角色和一个公司,用于表示具有时间定义的雇佣实例。随着我们对该工作具体内容的不断了解(如:工作地点),我们可以通过附加节点来丰富初始结构。
- 连接链表中的节点用于表示逻辑或时间顺序 通过使用不同的关系,我们甚至可以将链表交叉化。以电视节目集数为例,它可以在一个链表中连接以表示播出顺序(如:NEXT_BROADCAST关系),与此同时,也可以在另一个链表中连接用于表示其创作顺序(如:NEXT_IN_PRODUCTION关系)。相同的节点,相同的实体,确是两个不同结构。
InfoQ:我们可以讨论下图形遍历需求方面的设计考虑吗?
Jim & Ian: 与关系型数据库管理系统(RDBMS)不同,图形中的查询延迟与所要查询的图形数量成正比。而这意味着作为查询设计者,应尽量减少图形数量,将其控制在获取想要的答案范围即可。
在 Neo4j 中,这意味着你可以随意在查询中添加限制。这些限制可以防止数据库查询到的结果是你已知的无用路径。比如:在一大型社交图形中,如果你只对那些单身且与你有相同性取向 / 爱好 / 兴趣的人感兴趣,你大可以根据这些条件相应地限制你的查询。这样,你就可以避免结交那些跟你性取向不同 / 爱好无聊 / 兴趣奇怪的人。而你获取所需答案的速度也要快很多。
在 Cypher 中,我们可以非常粗略地表述那些匹配度很低的匹配,比如:
(me)-[*]->(other)
该查询匹配了对任意深度(其中的‘*’)及类型事务的所有关系类型。 其结果就是:该查询将多次遍历整个图形,进而影响了性能。反之,由于我们已知了某些领域不变量,我们将该查询优化为:
(me)-[:FRIEND]->()-[:FRIEND]->(other)
这样我们限制了关系类型及查询深度,只查找朋友的朋友(因为与自己朋友约会是个糟糕的主意)。尽管该查询比先前的有了一点点改善,但我们还可以更进一步优化。比如添加附加限制,像性别,性取向和兴趣等:
(me)-[:FRIEND]->()-[:FRIEND]->
(other:Heterosexual:Female)-[:LIKES]->
(:TV_SHOW {title: ‘Doctor Who’}).现在我们只要匹配到那些同样喜欢 Doctor Who 这一电视节目的异性恋女性(其它节点中的两个冒号分隔标签)。而 Neo4j 则可以大幅度地删减那些不匹配部分,从而大大降低了所需完成的工作量,缩短了延迟(针对大数据集,哪怕是几个小小的毫秒)。
InfoQ:在使用图形数据时,是否存在反面模式?
Jim & Ian:肯定存在一些反面模式会迷惑那些粗心的、或对图形建模不熟悉的人。比如,我们在 O’Reilly 系统《图形数据库》一书中讨论的邮件取证案例(第三章)。在这一案例中,我们需要查找组织内个人以交换信息为目的的潜在非法行为,比如类似内幕交易(参考安然事件)。
当设计图形建模是,我们通过阅读进行全面检查。假设我们手头有(Alice)-[:EMAILED]->(Bob)这一结构,我们可能会认为已经有了完善的模型,因为不管是从左到右(Alice 发邮件给 Bob),还是从右到左(Bob 收到 Alice 的邮件)都读起来特别通顺。
在最开始我们采用了这一模型,但很快发现其特别松散。当查询那些真正侵犯了通信规则的电子邮件时,却发现根本就不存在这些电子邮件,这可是一个大问题。此外,当我们期望看到那些能证明其腐败行为邮件时,我们却只能获知 Alice 和 Bob 曾互通过几次邮件。由于我们对英语的不精确使用,意外地将该主要领域实体,邮件本身,编译成了一种关系,而非节点。
幸运的是,一旦我们意识到所创建的模型是松散的,我们可以很直接地通过使用中间节点来改正:(Alice)-[:SENT]->(email)-[:TO]->(Bob)。现在我们有了代表邮件的中间节点,也知道了发件者(Alice)及其收件者(Bob)。拓展起来也简单,我们可同样捕获该邮件曾抄送或秘密抄送给谁:(Charlie)<-[: CC]-(email)-[:BCC]->(Daisy)。从这里可以很容易地看出我们将如何构建所有邮件交换这一大型图形,及如何绘制出能捕获任何破坏这些规则的模式。但是如果我们没有仔细考虑节点和关系的话,很可能就错过了这些内容。
如果对图形建模新来者有任何建议的话,那就是:不要(意外)将实体编译为关系。
InfoQ:你能讨论下图形数据库的难点或限制吗?
Jim & Ian:几年前,当我们从 RDBMS 转移到图形(当时我们还是 Neo4j 早期版本使用者,离产品开发还有很大的距离)遇到的最大挑战莫过于多年对关系建模根深蒂固的学习。很难摆脱先创建标准模型,然后为了性能而反规范这一设计流程。我们不敢相信图形会那么容易就成功,总觉得做得还不够多。
这点有的时候是很烦人的。只有花一些时间就能设计出具有高性能和逼真度的模型,然后接下来你却花费大量时间担心是否错过了某些东西。
幸运的是现在有大量的资料可以帮助大家快速熟悉图形数据库。比如:那些重点关注图形和 Neo4j 的优秀书籍、博客文章、Google 小组和健全的 Meetup 网站社区。随着对图形数据库的不断了解,以及对领域建模和查询工作的不断深入,那种做得不够多的感觉很快也就消失了。数据建模不再是个问题,而且也理应不是。
InfoQ:在数据查询,遍历和分析等领域,图数据管理空间中的标准当前处于什么状态?
Jim & Ian:其实对于大多数 NOSQL 存储而言,讨论标准还为时过早(Oracle 那群家伙可能会不同意这点)。在去年的 NOSQL Now! 会议中,大家普遍认为我们应标准化操作界面,这样用户可以将数据库插入到标准监测和警告基础架构中。而这也正在进行中。
现在谈论图形方面的特定标准确实过早。比如 Neo4j 最近才引入标签到节点,10 年以前这一概念并不存在于数据库历史中。随着图形数据库的不断发展,对模型和图形数据库中的这种急剧变革进行标准化还是操之过急:整个行业还很不成熟。图形数据库作为整个数据市场(RDBMS 和 NOSQL)发展最快的一部分,缺乏标准绝对不会成为其发展的阻碍。
与此同时,由于 Neo4j 占据了图形数据库超过 90% 的市场,其本身已是业界标准,它拥有众多的第三方连接器和框架可以将其插入到应用程序或监控堆栈中。
InfoQ:图形数据库总体上,尤其 Neo4j,它们的前景会是怎样?
Jim & Ian:图形是非常通用的数据模型。和 RDBMS 大体上类似,图形作为技术在过去一段时间里已经大范围地部署于不同领域。我们期望将来图形数据库能部署在更多领域。换句话说,当想到“数据库”时,我们期望图形数据库能成为默认选择及第一模型。
当然在此之前,我们还有一些事情需要解决。首先,图形数据库应更加容易使用,其开箱体验必须是无痛的,甚至是令人愉悦的。虽然该模型比起文档存储需要花费更多的学习时间(毕竟它是个内容更丰富的模型),但依然存在某些比较机械的东西我们可以改善以缩短学习曲线。
这点你可以从新版 Neo4j 2.0 的发布中看出:我们引进了标签到图形模型,并根据这些标签提供了声明式索引;构建了带有优秀可视化功能的新用户界面;以及拥有高生产力 REPL 的新版 Cypher。我们的努力不仅限于此:很快我们将发布一个修正版本,它将消除数据库大容量导入(所有用户至少执行过一次该操作)所带来的痛苦,之后我们也将不断提高 Neo4j 的易用性。
与此同时,我们也在研究和发展性能及规模。我们有些很好的想法,例如:根据数量级顺序并通过使用写窗口至批处理读写垂直拓展 Neo4j 中的 ACID 事务性写操作。从用户角度 Neo4j 依然保留对 ACID 的兼容,但是实际上我们将 IO 分摊在多个写操作上。然而这只在像 Neo4j 这样的原生图形数据库中才有可能,因为一直到磁盘我们都是自己控制代码,还可以相应地优化整个堆栈。而非原生图形数据库则没有这一选择。
对于大范围性能问题,由 Bailis et al 在 Highly-Available Transactions 里所作的工作让我们特别兴奋,它跨集群提供了无阻碍事务性协议。通过 RAMP 事务在数据库集群中维护 ACID 限制的同时,允许非竞争事务并行执行。在接下来的几个月大家会听到更多关于针对高度分布式图形数据库工作机械基础方面的想法。
关于受访者
Jim Webber目前是 Neo Technology 的首席科研人员,也是分布式系统专家,一直从事超大型图形数据技术方面的工作。
Ian Robinson是 Neo Technology 的一名工程师,同时担任 Neo 的客户成功项目(Customer Success)总监。一直与客户合作设计并开发关键任务(mission-critical)的图形数据库解决方案。
查看英文原 **** 文: Data Modeling in Graph Databases: Interview with Jim Webber and Ian Robinson
感谢陈菲对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
评论