首先,你需要问自己:一个顶点/节点的类型需要被索引吗?即您是否需要按类型检索顶点/节点,比如说,从图中检索所有“用户”顶点,或者您是否需要回答从检索给定类型的所有顶点开始的查询,然后进一步过滤/处理这些?
如果这个问题的答案是yes,那么我建议您将类型存储为索引的字符串属性。或者,如果您正在使用基于 jvm 的语言进行开发,您可以定义一个类型枚举并将其用作属性类型,以实现更多的类型安全和自动错误检查。Titan 支持任意用户定义的类/枚举作为属性类型,并将压缩它们以减少内存占用。
但是,这种方法的缺点是它不会扩展,因为您正在构建一个低选择性指数。这意味着可能会有很多类型为“用户”或“产品”的顶点,所有这些都需要分别与“用户”或“产品”的索引条目相关联。这使得维护和查询该索引非常昂贵且难以扩展(想象一下 facebook 有一个“类型”索引:“照片”条目下将有数十亿个顶点)。如果您(还)不关心缩放,那么这可以工作。
如果问题的答案是否定的,那么我建议将类型建模为图中的顶点/节点。即有一个“用户”顶点和一个“产品”顶点以及从每个用户到“用户”顶点的标记为“类型”的边等。
这种方法的优点是您可以使用图形对数据进行建模,而不是让数据库之外的字符串值代表关键的类型信息。在构建应用程序时,图形数据库将成为其中心组件并持续很长时间。随着编程语言和开发人员的来来去去,您不希望数据建模和类型信息与他们一起出现并面临以下问题:“SPECIAL_USER 是什么意思?” 相反,有一个 SPECIAL_USER 顶点并向其添加出处信息,即,谁创建了这种类型,它代表什么以及简短的描述——所有这些都在数据库中。
这种方法的一个问题是,当您的应用程序扩展时,“用户”和“产品”顶点将有很多边缘发生在它们身上。换句话说,您正在创建产生扩展问题的超级节点。这就是 Titan 引入单向边缘概念的原因。单向边就像网络上的链接:起始顶点指向另一个顶点,但该顶点不知道边。由于您不想从“用户”顶点遍历所有用户顶点,因此您不会失去任何东西,而是获得可伸缩性和性能。