使用Neo4j图数据库举例说明有几个原因。Neo4j是一个具有原生处理功能和原生图存储的图数据库。它的优点还在于透明度,因为它是开源的,这使富有冒险精神的读者可以很容易深入研究其代码。
6.1 原生图处理
假如图数据库存在免索引邻接属性,那么我们说它具有原生处理能力。
使用免索引邻接的数据库引擎中的每个节点都会维护其对相邻节点的引用。因此每个节点都表现为其附近节点的微索引,这比使用全局索引代价小很多。这意味着查询时间与图的整体规模无关,它仅和所搜索图的数量成正比。
相反,一个非原生图数据库引擎使用(全局)索引连接各个节点。这些索引对每个遍历都添加一个间接层,因此会导致更大的计算成本。原生图处理的拥护者认为免索引邻接至关重要,因为它提供快速、高效的图遍历。
索引查找在小型网络中可以工作,但对于大图的查询代价太高。具有原生图处理能力的图数据库在查询是不是使用索引查找来扮演联系的角色,而是使用免索引邻接来确保高性能遍历的。
6.2 原生图存储
如果免索引邻接是高性能遍历、查询和写入的关键,那么图数据库设计的一个关键方面是存储图的方式。高效的、本机化的图存储式支持任意图算法的极快遍历--这是使用图的重要原因。
节点存储文件用来存储节点的记录。每个用户级的图中创建的节点最终会终结于节点存储,其物理文件是"neostore.nodestore.db"。像大多数Neo4j存储文件一样,节点存储区是固定大小的记录存储,每个记录长度为9字节。通过大小固定的记录可以快速查询存储文件中的节点。
一个节点记录的第一个字节是“是否在使用”标志位。它告诉数据库该记录目前是被用于存储节点,还是可回收用于表示一个新的节点。接下来的4字节表示关联到该节点的第一个联系,随后4字节表示该节点的第一个属性的ID。标签的5字节指向该节点的标签存储(如果标签很少的话也可以内联到节点中)。最后的字节extra是标志保留位。这样一个标志是用来标识紧密连接节点的,而省下的空间为将来预留。节点记录是相当轻量级的:它真的只是几个指向联系和属性列表的指针。
相应的,联系被存储于联系存储文件中,物理文件是neostore.relationshipstore.db。像节点存储一样,联系存储区的记录的大小也是固定的。每个联系记录包含联系的起始点ID和结束节点ID、联系类型的指针(存储在联系类型存储区),起始节点和结束节点的上一个联系和下一个联系,以及一个指示当前记录是否位于联系链最前面。
两个节点记录都包含一个指向该节点的第一个属性的指针和联系链中第一个联系的指针。要读取节点的属性,我们从指向第一个属性的指针开始遍历单向链表结构。要找到一个节点的联系,我们从指向第一个联系(在示例中为LIKES联系)的节点联系指针开始,顺着特定节点的联系的双向链表寻找(即起始节点的双向链表或结束节点的双向链表),直到找到感兴趣的联系。一旦找到了我们想要的联系记录,我们可以使用和寻找节点属性一样的单向链表结构读取这种联系的属性(如果有的话),也可以使用联系关联的起始节点ID和结束节点ID检查它们的节点记录。用这些ID乘以节点记录的大小,就可以立即算出每个节点在节点存储文件中的偏移量。
联系存储文件中的双向链表:
6.3 用于编程的API
6.4 非功能型特性
事务
可恢复性
可用性
可扩展性