Neo4j【从无到有从有到无】【N2】存储连接数据的选项

目录

1.关系数据库缺少关系

2.NOSQL数据库也缺乏关系

3.图形数据库拥抱关系

4.摘要


我们生活在一个互联的世界中。 为了蓬勃发展,我们需要了解并影响我们周围的联系网络。

当今的技术如何应对互联数据的挑战? 在本章中,我们研究关系数据库和聚合NOSQL存储如何管理图和连接的数据,并将它们的性能与图数据库的性能进行比较。 对于有兴趣探索NOSQL主题的读者,附录A描述了NOSQL数据库的四种主要类型。

1.关系数据库缺少关系

数十年来,开发人员一直试图在关系数据库中容纳连接的半结构化数据集。 但是,尽管关系数据库最初被设计为将纸质表格和表格结构进行编纂,但是在尝试对现实世界中出现的特殊,特殊关系进行建模时,它们确实非常费劲。 具有讽刺意味的是,关系数据库对关系的处理不善。

关系确实存在于关系数据库的本地语言中,但仅在建模时才作为连接表的一种方式。 在上一章对连接数据的讨论中,我们提到我们经常需要消除连接实体关系的语义的歧义,并确定其权重或强度。关联关系无济于事。 更糟糕的是,随着异常数据的增加,数据集的整体结构变得更加复杂和不统一,关系模型变得负担重,需要大的联接表,稀疏的行以及大量的空检查逻辑。 连接性的提高在关系世界中转化为连接的增加,这阻碍了性能,并使我们难以响应不断变化的业务需求而发展现有数据库。

图2-1显示了用于在以客户为中心的交易应用程序中存储客户订单的关系架构。

该应用程序对该模式的设计产生了巨大的影响,使某些查询非常容易,而另一些则更加困难:

  • 连接表增加了意外的复杂性; 他们将业务数据与外键元数据混合在一起。
  • 外键约束只是为了使数据库正常工作而增加了额外的开发和维护开销。
  • 尽管存在模式,但具有可空列的稀疏表仍需要对代码进行特殊检查。
  • 仅需几个昂贵的联接即可发现客户购买了什么。
    • 相互查询的成本更高。 与“哪些客户购买了该产品?”相比,“客户购买了哪些产品?”相对便宜,后者是推荐系统的基础。 我们可以引入一个索引,但是即使有了索引,也会出现递归问题,例如“哪些客户购买了该产品,还购买了该产品?”随着递归程度的提高,其价格很快变得高得惊人。

关系数据库在高度连接的域中挣扎。要了解在关系数据库进行连接查询的费用,我们来看看一些简单的和在社交网络领域不那么简单查询。

图2-2显示了用于记录友谊的简单联接表安排。

如例2-1所示,询问“鲍勃的朋友是谁?”很容易。

示例2-1 鲍勃的朋友

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'

根据我们的样本数据,答案是Alice和Zach。 这不是特别昂贵或困难的查询,因为它使用过滤器WHERE Person.person ='Bob'限制了所考虑的行数

友谊并不总是一种自反的关系,因此在示例2-2中,我们提出了对等查询,即“谁与Bob成为朋友?”

示例2-2 谁是鲍勃的朋友?

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'

该查询的答案是Alice; 遗憾的是,扎克不认为鲍勃是朋友。 这种相互查询仍然易于实现,但在数据库方面则更为昂贵,因为数据库现在必须考虑PersonFriend表中的所有行。

我们可以添加一个索引,但这仍然涉及一个昂贵的间接层。 当我们问“谁是我的朋友的朋友?”时,问题变得更加棘手,SQL的层次结构使用了递归联接,这使查询在语法和计算上变得更加复杂,如示例2-3所示。 (某些关系数据库为此提供了语法糖(例如,Oracle具有CONNECT BY函数),该函数简化了查询,但没有简化基础的计算复杂性。)

例2-3爱丽丝的朋友

SELECT p1.Person AS PERSON, p2.Person AS FRIEND_OF_FRIEND
FROM PersonFriend pf1 JOIN Person p1
ON pf1.PersonID = p1.ID
JOIN PersonFriend pf2
ON pf2.PersonID = pf1.FriendID
JOIN Person p2
ON pf2.FriendID = p2.ID
WHERE p1.Person = 'Alice' AND pf2.FriendID <> p1.ID

即使仅与Alice的朋友的朋友打交道,该查询在计算上也很复杂,并且不会深入到Alice的社交网络。 我们进入网络越深入,事情就变得越复杂,越昂贵。 尽管有可能在合理的时间内回答“谁是我的朋友的朋友?”的问题,但由于友谊程度高,扩展到四,五或六度的查询会大大恶化。 递归联接表的计算和空间复杂度。

每当我们尝试在关系数据库中对连接进行建模和查询时,我们都会采取行动。除了上面概述的查询和计算复杂性之外,我们还必须处理架构的双刃剑。 schema经常被证明既太僵硬又太脆。 为了破坏其刚性,我们创建了具有许多可空列的稀疏填充表,并编写了代码来处理特殊情况-所有这些都是因为没有真正的“一刀切”的架构来适应我们遇到的数据的多样性。 这增加了耦合并且几乎破坏了任何内聚的表象。 它的脆弱性表现为随着应用程序的发展从一种模式迁移到另一种模式所需的额外工作和精力。

2.NOSQL数据库也缺乏关系

大多数NOSQL数据库(无论是键值,面向文档还是面向列)都存储断开连接的文档/值/列的集合。 这使得很难将它们用于连接的数据和图形。

向此类商店添加关系的一种众所周知的策略是将集合的标识符嵌入到另一个集合的字段中,从而有效地引入外键。 但这需要在应用程序级别加入聚合,这很快变得非常昂贵。

当我们查看一个聚合商店模型(例如图2-3中的模型)时,我们想象我们可以看到关系。 在记录起始用户:Alice中看到对order:1234的引用,我们推断出用户:Alice和order:1234之间的连接。 这给了我们错误的希望,那就是我们可以使用键和值来管理图形。

在图2-3中,我们推断出某些属性值实际上是对数据库中其他位置的外部聚合的引用。 但是将这些推论转变为可导航的结构并不是免费的,因为聚合之间的关系并不是数据模型中的一等公民—大多数聚合存储仅以嵌套地图的形式提供具有结构的聚合内部。 取而代之的是,使用数据库的应用程序必须从这些平坦的,断开连接的数据结构中建立关系。 我们还必须确保应用程序与其余数据一起更新或删除这些外部集合引用。 如果这种情况没有发生,那么商店将积累悬挂的引用,这会损害数据质量和查询性能。

Links and Walking

Riak键值存储允许使用链接元数据来扩充其每个存储的值。 每个链接都是单向的,从一个存储的值指向另一个。 Riak允许行走任意数量的这些链接(使用Riak术语),从而使模型有所关联。 但是,此链接漫游由map-reduce提供支持,这是相对潜在的。 与图形数据库不同,此链接仅适用于简单的图形结构编程,而不适用于常规图形算法。

该方案还有另一个弱点。 因为没有“向后”指向的标识符(当然,外部聚合“链接”不是自反的),所以我们失去了在数据库上运行其他有趣查询的能力。 例如,使用图2-3中所示的结构,询问数据库谁购买了特定产品(可能是为了基于客户的个人资料提出建议)是一项昂贵的操作。 如果我们想回答此类问题,我们可能最终会导出数据集并通过某些外部计算基础架构(例如Hadoop)对其进行处理,以蛮力计算结果。 或者,我们可以追溯地插入向后指向的外部聚合引用,然后查询。为了结果。 无论哪种方式,结果都是潜在的。

诱人的是,就连接数据而言,聚合存储在功能上等同于图形数据库。 但这种情况并非如此。 聚合存储不维护连接数据的一致性,也不支持所谓的无索引邻接,即元素包含指向其邻居的直接链接。 结果是,对于连接的数据问题,聚合存储必须使用固有的潜在方法来创建和查询数据模型外部的关系。

让我们看看其中的一些局限性是如何表现出来的。 图2-4显示了一个小型社交网络,该社交网络是使用聚合商店中的文档实现的。

通过这种结构,很容易找到用户的直接朋友-当然,假设该应用程序已尽力确保存储在friends属性中的标识符与数据库中的其他记录ID一致。 在这种情况下,我们只需按直系朋友的ID查找直属朋友,这需要进行大量索引查找(每个朋友一个),但无需对整个数据集进行强力扫描。 这样做,例如,我们发现鲍勃认为爱丽丝和扎克是朋友。

但是友谊并不总是对称的。 如果我们想问“谁是鲍勃的朋友?”而不是“谁是鲍勃的朋友?”怎么办?这是一个较难回答的问题,在这种情况下,我们唯一的选择是对整个对象进行暴力扫描 寻找包含Bob的朋友条目的数据集。

O标记和蛮力处理

我们使用O表示法来描述算法的性能如何随数据集的大小而变化。 O(1)算法表现出恒定的时间性能; 也就是说,无论数据集的大小如何,算法都需要花费相同的时间来执行。 O(n)算法表现出线性性能; 当数据集加倍时,执行算法所需的时间加倍。 O(log n)算法表现出对数性能; 当数据集增加一倍时,执行算法所需的时间将增加固定量。 当数据集处于初期阶段时,相对性能的提高可能看起来代价很高,但是随着数据集变得更大,它会迅速消失。 O(m log n)算法是本书中考虑的最昂贵的算法。 使用O(m log n)算法,当数据集增加一倍时,执行时间将增加一倍,并增加与数据集中元素数量成正比的一些额外量。

由于必须考虑数据存储中的所有n个聚合,因此就复杂性而言,蛮力计算整个数据集为O(n)。 对于大多数人来说,这太昂贵了。

大小合理的数据集,我们更喜欢使用O(log n)算法(这种算法效率很高,因为它在每次迭代时都会丢弃一半的潜在工作量),甚至更好。

相反,图形数据库为同一查询提供恒定顺序的查询。 在这种情况下,我们只需要在图中找到代表Bob的节点,然后遵循所有传入的朋友关系即可; 这些关系导致结点代表代表认为Bob是他们的朋友的人。 这比暴力破解结果便宜得多,因为它认为网络的成员要少得多。 也就是说,它仅考虑连接到Bob的那些。 当然,如果非常与Bob成为朋友,我们仍然会考虑整个数据集。

为了避免必须处理整个数据集,我们可以通过添加反向链接来对存储模型进行规范化。 向每个用户添加第二个属性(也许称为frien ded_by),我们可以列出与该用户关联的传入友谊关系。 但这不是免费的。 对于初学者,我们必须支付增加的写延迟的初始和持续成本,以及用于存储其他元数据的增加的磁盘利用率。 最重要的是,遍历链接仍然很昂贵,因为每个跃点都需要索引查找。 这是因为聚集不具有局部性的概念,这与图形数据库不同,图形数据库自然通过真实(而不是固定的)关系提供无索引的邻接。 通过在非本地商店的顶部实现图结构,我们可以获得部分连接的一些好处,但是成本很高。

遍历比一跳更深的步伐时,这种巨大的成本将被放大。 朋友很容易,但是想像一下要实时计算“朋友的朋友”或“朋友的朋友的朋友”。 使用这种数据库是不切实际的,因为遍历假关系并不便宜。 这不仅限制了您扩展社交网络的机会,还减少了可获利的建议,丢失了数据中心中的故障设备,并使欺诈性的购买活动通过网络流失。 许多系统试图保持图形化处理的外观,但是不可避免地要分批完成,并且不能提供用户所需的实时交互。

3.图形数据库拥抱关系

前面的示例处理了隐式连接的数据。 作为用户,我们可以推断实体之间的语义依赖关系,但是数据模型以及数据库本身对这些连接不了解。 为了进行补偿,我们的应用程序必须从平坦的,断开连接的数据中创建一个网络,然后处理出现在非规范化存储中的所有慢速查询和潜在写入。

我们真正想要的是整体的凝聚力图景,包括元素之间的联系。 与我们刚刚看过的商店相反,在图表世界中,关联数据存储为关联数据。 域中存在连接的地方,数据中也存在连接。 例如,考虑图2-5中所示的社交网络。

在这种社交网络中,就像在现实世界中连接数据的许多情况下一样,实体之间的连接在整个域中并没有表现出统一性,域是可变结构的。 社交网络是紧密连接,可变结构的网络的流行示例,该网络拒绝被一种适合所有人的模式捕获,也可以方便地拆分为多个断开的聚合。 我们简单的朋友网络规模不断扩大(现在,潜在的朋友可以达到6度),富有表现力。 图模型的灵活性使我们能够添加新节点和新关系,而不会损害现有网络或迁移数据,原始数据及其意图保持不变。

该图提供了更丰富的网络图。 我们可以看到谁爱谁(以及这种爱是否得到回报)。 我们可以看到谁是COLLEAGUE_OF谁,谁是BOSS_OF。 我们可以看到谁在市场之外,因为他们是MARRIED_TO其他人; 我们甚至可以在DISLIKES关系所代表的社交网络中看到反社会元素。 有了这个图形,我们现在可以查看图形数据库在处理连接数据时的性能优势。

图中的标签

通常,我们希望根据网络中的节点所扮演的角色对其进行分类。 例如,某些节点可能代表用户,而另一些节点代表订单或产品。 在Neo4j中,我们使用标签来表示节点在图中扮演的角色。 由于一个节点可以在图中扮演多个不同的角色,因此Neo4j允许我们向一个节点添加多个标签。

通过这种方式使用标签,我们可以对节点进行分组。 例如,我们可以要求数据库查找所有标记为User的节点。 (标签也为声明式索引节点提供了一个钩子,我们将在后面看到。)在本书的其余示例中,我们将广泛使用标签。 在节点代表用户的地方,我们添加了用户标签; 在代表订单的位置,我们添加了“订单”标签,依此类推。 我们将在下一章中解释语法。

图中的关系自然形成路径。 查询或遍历该图涉及以下路径。 由于数据模型的本质是面向路径的,因此大多数基于路径的图数据库操作与数据的布局方式高度一致,从而使其极为高效。 Partner和Vukotic在他们的《行动中的Neo4j》一书中使用关系商店和Neo4j进行了实验。 比较表明,图数据库(在本例中为Neo4j及其遍历框架)比关系存储要快得多。

Partner和Vukotic的实验旨在在社交网络中找到朋友的朋友,最大深度为5。 对于包含1,000,000人(每个人约有50个朋友)的社交网络,结果强烈表明,图数据库是连接数据的最佳选择,如表2-1所示。

表2-1. 在关系数据库中查找扩展的朋友与Neo4j中的有效查找

在第二层(朋友的朋友),关系数据库和图形数据库的性能都足够好,我们可以考虑在在线系统中使用它们。 尽管Neo4j查询的运行时间是关系查询的三分之二,但最终用户几乎不会注意到两者之间的毫秒差。 但是,到了深度三(朋友的朋友的朋友)时,很明显,关系数据库不再能够在合理的时间范围内处理查询:完成这30秒将完全 在线系统无法接受。 相比之下,Neo4j的响应时间仍然相对平稳:执行查询只需几分之一秒,对于在线系统而言绝对足够快。

在深度四处,关系数据库表现出严重的延迟,这使其几乎对在线系统毫无用处。 Neo4j的时间安排也略有恶化,但是延迟在响应型在线系统可接受的范围之内。最后,在第5层深度,关系数据库仅花费太长时间来完成查询。 相反,Neo4j在大约两秒钟内返回结果。 在深度5,事实证明几乎整个网络都是我们的朋友。 因此,对于许多实际使用案例,我们可能会调整结果,从而减少时间。

当我们远离大小适中的集合操作(它们都应该擅长的操作)时,聚合存储和关系数据库的性能都较差。 当我们尝试从图中挖掘路径信息时,事情就变慢了,就像“朋友的朋友”的例子一样。 我们并不是要在综合商店或关系数据库上过分强调。 他们在擅长的事情上拥有出色的技术血统,但是在管理连接的数据时却不足。 由于所涉及的索引查找次数众多,因此除了缓慢遍历直系朋友或可能的亲友之外,其他所有操作都将很慢。 另一方面,图形使用无索引的邻接关系来确保遍历连接的数据非常快。

社交网络示例有助于说明不同的技术如何处理连接的数据,但这是有效的用例吗? 我们真的需要找到这样的偏远的“朋友”吗? 也许不是。 但是,用其他任何域替换社交网络,您都会看到我们在性能,建模和维护方面都享有类似的好处。 无论是音乐或数据中心管理,生物信息学或足球统计数据,网络传感器还是交易时间序列,图表都可以为我们的数据提供强大的洞察力。 然后,让我们看一下图表的另一种当代应用:根据用户的购买历史以及他的朋友,邻居和其他类似他的历史来推荐产品。 在此示例中,我们将汇总用户生活方式的几个独立方面,以提供准确且有利可图的建议。

首先,将用户的购买历史记录建模为关联数据。 在图形中,这就像将用户链接到她的订单,然后将订单链接在一起以提供购买历史记录一样简单,如图2-6所示。

图2-6中显示的图形提供了对客户行为的大量洞察。 我们可以看到用户已下订单的所有订单,并且我们可以轻松推断每个订单包含哪些内容。 然后,在此核心域数据结构中,我们添加了对几种知名访问模式的支持。 例如,用户经常想查看他们的订单历史记录,因此我们在图表中添加了一个链接列表结构,使我们可以通过遵循传出的MOST_RECENT关系来查找用户的最新订单。 然后,我们可以通过跟踪每个上一个关系来遍历列表,以进一步追溯到上一个列表。 如果我们想及时前进,我们可以沿相反的方向遵循每个上一个关系,或者添加一个互惠的下一个关系。

现在我们可以开始提出建议了。 如果我们发现许多购买草莓冰淇淋的用户也购买了特浓咖啡,那么我们可以开始向那些通常只购买冰淇淋的用户推荐这些咖啡豆。 但这是一个一维的建议:我们可以做得更好。 为了增加图表的功能,我们可以将其加入其他域的图表。 由于图自然是多维结构,因此直接询问更复杂的数据问题就可以直接进入经过微调的细分市场。 例如,我们可以要求该图为我们找到“那些喜欢浓咖啡但不喜欢抱子甘蓝并且生活在某个街区的人们喜欢的所有冰淇淋口味”。

为了解释数据,我们可以考虑某人重复购买某种产品的程度来表明他们是否喜欢该产品。 但是,我们如何定义“住在附近”呢? 好吧,事实证明,地理空间座标非常方便地建模为图形。 用于表示地理空间座标的最受欢迎的结构之一称为R-Tree。R-Tree是一种类似图形的索引,它描述了地理周围的有界框。 使用这种结构,我们可以描述重叠的位置层次结构。 例如,我们可以表示一个事实,即伦敦在英国,而邮政编码SW111BD在英国的东南部伦敦,又是英国的伦敦的特特西。 而且由于英国邮政编码是细粒度的,因此我们可以使用该边界来定位具有相似品味的人群。

这种模式匹配查询在SQL中极难编写,并且很难对聚合存储进行编写,并且在两种情况下,它们的性能都非常差。 另一方面,图形数据库针对这些类型的遍历和模式匹配查询进行了优化,在许多情况下可提供毫秒级的响应。 而且,大多数图数据库提供适合于表达图构造和图查询的查询语言。 在下一章中,我们将介绍Cypher,这是一种模式匹配语言,已根据我们倾向于使用图表来描述图形的方式进行了调整。

我们可以使用示例图向用户提出建议,但也可以使用它使卖方受益。 例如,给定某些购买模式(产品,典型订单的成本等),我们可以确定特定交易是否具有欺诈性。 可以轻松地在图形中检测到给定用户超出规范的模式,然后将其标记出来以引起进一步关注(使用图形数据挖掘文献中的众所周知的相似性度量),从而降低了卖方的风险。

从数据从业者的角度来看,很明显,图形数据库是处理复杂,可变结构,密集连接的数据的最佳技术,也就是说,数据集是如此复杂,以图形以外的任何形式处理时都不方便。

4.摘要

在本章中,我们了解了关系数据库和NOSQL数据存储中的连接性如何要求开发人员在应用程序层中实现数据处理,并与图数据库进行了对比,在图数据库中,连接性是一等公民。 关于图形建模的更多详细信息。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章