本节书摘来自异步社区出版社《图数据库(第2版)》一书中的第2章,第2.3节,作者:【美】Ian Robinson(伊恩•罗宾逊) , Jim Webber(吉姆•韦伯) , Emil Eifrem(埃米尔•艾弗雷姆),更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.3 图数据库拥抱联系
前面的例子处理了隐式的
关联数据。作为用户,我们推断实体之间的语义相关性,但数据模型与数据库本身却忽视了这些关联。为了弥补这一点,我们的应用程序必须着手创建一个扁平的、无连接的数据之外的网络,然后再处理那些由反规范化存储导致的缓慢查询和延迟写入。
我们真正想要的是一个全景图,包括元素之间的关联。与我们之前看到的不同,在图的世界中,关联数据被存储为关联数据
。只要问题域中存在关联,数据中就存在关联,如图2-5表示的社交网络。
在这个社交网络中,有如此多的实际情景中的关联数据,但实体之间的关联在领域之间并没有表现得一致—域是结构可变的。社交网络是一个非常流行的密集关联、结构可变的网络的例子,它不该被作为一个普适模式,也不该被分割成多个无关联的聚合数据。这个简单的朋友网络已经在规模上成长(潜在的朋友关系的距离已经深达6度),在表现力上丰富起来。图模型的灵活性使我们能增加新的节点和新的联系,与此同时不影响现有网络,也不用做数据迁移—原始数据和其意图都保持不变。
这个图为该网络提供了更丰富的信息。我们可以看到谁LOVES(爱着)谁(无论这爱是不是在单相思),也可以看到谁是谁的COLLEAGUE_OF(同事),谁是所有人的BOSS_OF(老板)。我们可以看到谁远离市场,因为他们和别人是MARRIED_TO(结婚)联系。我们甚至可以在其他社交网络中发现不善交际的元素,用DISLIKES(不喜欢)联系来表示。有了我们所掌握的这个图,我们现在就可以看看图数据库在处理关联数据时的性能优势了。
图中的关系自然地形成了路径。查询图或是遍历图都涉及路径。由于从根本上说,数据模型是面向路径的,多数基于路径的图数据库的操作都与数据模型本身呈现高度一致性,因此它们极为高效。在Neo4j in Action
一书中,Partner
和Vukotic
同时使用关系存储和Neo4j
进行实验。实验通过对比表明,在处理关联数据方面,图数据库(这里是指Neo4j
及其遍历框架)比关系存储要快得多。
图中的标签
我们市场希望在网络中通过节点所扮演的角色对其进行分类。比如,有些节点可能代表用户,而其他的代表订单或产品。在Neo4j中,使用labels表示节点在图中扮演的角色。由于一个节点在图中可以满足多种不同角色,因此Neo4j允许用户对一个节点添加多个标签。
这样使用标签可以对节点分类。比如,我们可以询问数据库来寻找所有标签为User的节点。(标签也提供了钩子来声明式地索引节点,之后会提及。)本书后面部分的示例中会广泛用到标签。我们给表示用户的节点添加User标签,给表示订单的节点添加Order标签,诸如此类。下一章将会解释标签的语法。
Partner和Vukotic的实验试图在一个社交网络里找到最大深度为5的朋友的朋友。对于一个包含100万人,每人约有50个朋友的社交网络,结果明显表明,图数据库是用于关联数据的最佳选择,如表2-1所示。
在深度为2时(即朋友的朋友),假设在一个在线系统中使用,无论关系型数据库还是图数据库,它们的执行时间都表现得足够好。虽然Neo4j的查询时间是关系数据库的2/3,但终端用户很难注意到两者间毫秒级的时间差异。当深度为3时(即朋友的朋友的朋友),很明显关系型数据库无法在合理的时间内实现查询了:一个在线系统无法接受30 s的查询时间。相比之下,Neo4j的响应时间则保持相对平坦:执行查询仅需要不到1 s,这对在线系统来说足够快了。
在深度为4时,关系型数据库表现出很严重的延迟,使其无法应用于在线系统。Neo4j所花时间也有所增加,但其时延处于在线系统的可接受范围内。最后,在深度为5时,关系型数据库所花时间过长以至于没有完成查询。相比之下,Neo4j在2 s左右的时间就返回了结果。在深度为5时,事实证明几乎整个网络都是我们的朋友。因此,在很多实际用例中,我们可能需要修剪查询结果,从而缩短时长。
聚合存储和关系型数据库对于超出中等规模的集合操作(那些它们本该做得不错的)表现得都不太好。当我们试图从图中挖掘路径信息时(比如朋友的朋友那个例子),操作慢了下来。我们并非想要贬低聚合存储和关系型数据库。它们在各自所擅长的方面有很好的技术能力,但在管理关联数据时却无能为力。任何超出寻找直接朋友或是寻找朋友的朋这样的浅遍历的查询,都将因为涉及的索引数量过多而使查找变得缓慢。而图数据库由于使用了免索引邻接,确保了遍历关联数据是非常迅速的。
社交网络这个例子有助于说明不同的技术是如何处理关联数据的,但它是否是有效用例呢?我们是否真的需要寻找这样远的“朋友”呢?也许不是。但将社交网络替换为任何其他领域时,你会发现我们在性能、建模和维护方都能面获得类似的好处。无论是音乐领域还是数据中心管理,无论是生物信息还是足球统计,无论是网络传感器还是时序交易,图都能对这些数据提供强有力而深入的理解。让我们来看看图在当代的另一个应用:基于用户自己的购买历史和他的朋友、邻居以及其他喜欢他的人的购买历史为他推荐商品。这个例子中,我们能将用户生活方式中多个独立的方面汇集起来,做出准确而有商业意义的推荐。
首先,我们将用户的购买历史建模为关联数据。这在图中很简单,只需将用户和他的订单链接起来,然后我们再将这些订单链接为购买历史,如图2-6所示。
图2-6所示的图深入洞察了消费者的行为。我们可以看到用户已经订购(PLACED
)的所有订单,同时可以容易地推出每个订单包含(CONTAINS
)了什么。对这个核心领域数据结构,我们已经添加了对几种熟知的访问模式的支持。例如,用户往往希望看到自己的订单历史,因此我们在图中增加一个链表结构,这样我们可以通过向外的最近(MOST_RECENT
)联系找到用户最近的订单。随后,我们可以通过迭代该链表,沿着每个上一个(PREVIOUS
)联系回溯到更早的订单。如果我们希望找到更近的订单,我们则可以反向寻找PREVIOUS
联系,或者添加一个反向的下一个(NEXT
)联系。
现在我们可以开始进行推荐了。如果我们发现许多购买草莓冰淇淋的用户还购买了意大利咖啡豆,我们就可以推荐那些通常只买冰淇淋的用户也去买意大利咖啡豆。这只不过是个一维的推荐:我们可以做得更好。为了提高图的能力,我们可以将其与其他领域的图连接起来。由于图天然是多维结构,所以可以更直接地提出更复杂的问题,以此获得市场需要微调的部分。例如,我们可以通过图知道“喜欢意式咖啡但不喜欢球芽甘蓝的人喜欢什么口味的冰淇淋,以及哪些人住在某个特定的街区。”
为了解释数据,我们需要考虑反复购买同一商品的用户在多大程度上象征着他喜欢这款商品。但如何才能定义“住在附近”?事实证明,地理坐标可以被很方便地建模为图。最流行的表示地理坐标的结构被称为R树
。R树是描述有边界区域的类图索引。使用这样的结构可以描述地理区域的重叠层次。例如,我们可以陈述一个事实,伦敦在英国,邮编为SW111BD的地方在巴特西,这是伦敦的一个区域,伦敦在英格兰的东南部,而英格兰在英国。而由于英国的邮政编码粒度很细,因此可以把邮编作为标准来界定有相似口味的目标人群。[1]
在SQL中或是聚合存储中写这样的模式匹配查询都非常困难,并且其查询性能都很不好。而图数据库在这方面做了优化,能够在这类遍历和模式匹配查询方面提供精确到毫秒级别的响应。此外,多数图数据库提供了适合表达图结构和图查询的查询语言。下一章我们将讲解Cypher,这是一个适合描述图的模式匹配语言。
除了可以用例子中的图向用户进行推荐,我们还能借此使卖方获益。例如,对于某些购买模式(商品、典型订单的价格等),我们能建立模式来判断特定的事务是否是潜在的欺诈。通过图可以很简单地识别特定用户的非常规模式,进而能将其标记出来用于进一步关注(可以使用关于图的数据挖掘文献中的知名的相似性度量方法),从而减少卖方的风险。[2]
从数据从业者的角度来看,很明显,图数据库是处理复杂的、结构可变的、密集关联的数据的最好的技术,也就是说,对于如此复杂的数据,使用别的方式处理远不如使用图实用。