在图形数据库中存储标记

Storing tags in a graph database

本文关键字:存储 图形数据库      更新时间:2023-09-26

我找到了一些在关系和文档数据库中设置标记系统的建议,但没有关于图形/多模型数据库的建议。

我正在尝试在ArangoDB中为文档(我们称之为"文章")设置一个标记系统。我可以想到两种明显的方法来将标签存储在像 Arango 这样的多模型(图形+文档)数据库中:

  • 作为每个项目文档中的数组(文档数据库样式)
  • 作为一个
  • 单独的文档类,每个标签作为一个唯一的文档,并将标签文档连接到文章文档的边缘(更接近关系数据库样式)

这实际上是实现此目的的两种主要方法吗?两者似乎都不理想。例如:

  • 如果我在每个文章文档中存储标签,我可以索引标签,大概 ArangoDB 正在优化它们使用的空间。但是,我不能使用图形特征来链接或遍历标签(或者我必须单独进行)。
  • 如果我将标签存储为单独的标签文档,那么当我只想获取文档上的标签列表时,这似乎是额外的开销(额外的查询)。

这让我想到了一个明确的问题:关于后一种选择,是否有任何简单的方法可以自动使连接的"标签"文档显示在文章文档中? 例如,有一个数组属性以某种方式"镜像"了连接的标签文档的tag.name属性?

也欢迎一般建议。

@Joachim Bøggild 链接到 Mike Williamson: https://mikewilliamson.wordpress.com/2015/07/16/data-modeling-with-arangodb/

我同意威廉姆森的观点,即"默认紧凑"通常是要走的路。然后,如果出现实际需求,您可以从属性中提取顶点(也称为节点)。它还避免了创建过度互连的图形结构,这对于所有类型的遍历查询来说都会很慢。

但是,在这种情况下,我认为拥有标签顶点(即您的术语中的"文档")是件好事,因为您可以将元数据存储在标签上(如计数),并将其连接到其他标签和子标签。在标签的特定情况下,这似乎非常有用并且可以立即预见。拥有一个顶点,您可以在需要时添加更多关系,这也是非常可扩展的,因此您可以保持未来的选择更加开放(至少更容易)。

威廉姆森似乎同意标签值得特别考虑

"但并非一切都属于一起。任何包含复杂的数据结构(如"注释"数组或"标签"数组)值得一提,因为它作为顶点可能有意义(或顶点)自己的。

@ropeladder的原始问题提出了主要的反对意见,即它需要额外的开销(额外的查询)。我认为在这个阶段过多考虑性能可能是过早的优化。毕竟;额外的查询可能很快,或者实际上可能与原始查询联接并包含在原始查询中。无论如何,我会引用这一点:

"一般来说,试图合并节点以保留节点是一种不好的做法。查询时效率。如果我们根据以下问题进行建模想要询问我们的数据,域的准确表示将出现。图形数据库即使在存储时也能保持快速查询时间海量数据。学会信任我们的图形数据库是在学习在不非规范化的情况下构建我们的图形时很重要他们。---来自第64页"避免反模式"一章,在"图数据库"一书中,这是一本由Neo4j的创始人Eifrem共同撰写的书,另一个非常流行的本机图形数据库。它是免费的,可在线获得这里: https://neo4j.com/graph-databases-book/

另请参阅这篇关于一些反模式(密集图与稀疏图)的文章,以补充威廉姆森的观点: https://neo4j.com/blog/dark-side-neo4j-worst-practices/

<小时 />

为了完整起见,包括额外的部分,对于那些想要更深入地研究这个问题的人:

回答威廉姆森自己的标准,以决定某物是否应该成为顶点/节点,而不是将其保留为文档顶点上的属性:

它会自行访问吗?(即:显示没有文档的标签)

是的。系统中可用的浏览标签可能很有用。

您会对其运行图形测量(如GRAPH_BETWEENNESS)吗?

拿不准。应该不会。

它会自己编辑吗?

是的,可能。用户可以单独编辑它。也许管理员/版主想要清理标签名称(更正拼写错误)或清理其结构(如果您有子标签)。

标签是否/可以有自己的关系?(假设你在乎)

是的。他们可以。子标记或其他类型的内容,而不仅仅是文档。实际上,能够单击标签并立即查看具有该标签的所有文档非常有用。如果标签存储为每个文档上的属性数组,这可能是次优的。而图形数据库从根本上针对查询与其他顶点(也称为节点)相邻的顶点的情况进行了优化。

如果没有它的父顶点,此属性会/应该存在吗?

是的。即使删除了最后一个标记的文档,标记也可能/应该存在。有人可能希望稍后使用该标记,它表示您可能想要保留的域信息。

<小时 />

您已经提到了大多数可用的决策标准。也许我可以再添加一些:

文档中的关系标签可以使用数组索引来过滤它们,这可以快速查询它们。但是,如果您想为该标签数组的每个项目添加评级或解释,则没有办法。如果要计算标记的文档,这可能也比计算源自特定标记的所有边缘或查找与搜索条件匹配的所有标记更昂贵。

多模型的优势之一是,您不需要在这两种方法之间做出决定。您可以使用一个边缘集合将具有属性的标签连接到文档,并在文档中具有具有相同(平面)标签的索引数组。如果您发现所有(或大多数)查询仅使用一种方法,请尝试转换其余查询并删除其他解决方案。如果这不起作用,您的应用程序只需要它们。

这两种情况下,都可以在子查询中查找其他标记的文档:

LET docs=(FOR ftDoc IN FULLTEXT(articles, 'text', 'search')
    COLLECT tags = ftDoc.tags INTO tags RETURN {tags, ftDoc})
LET tags = FLATTEN(FOR t IN docs[*].tags RETURN t)
LET otherArticles = (FOR oneTag IN tags 
    FOR oneD IN articles FILTER oneTag IN oneD.tag RETURN oneD._key)
RETURN {articles: docs, tags: tags, otherArticles: otherArticles}

不幸的是,关于连接的文档是否可以自动显示在文档中的明确问题的答案是否定的。我已经制作了一个带有单独标签文档的 ArangoDB 图,但我正在认真考虑将其转换为单个项目的属性,因为这些标签似乎遵循属性而不是相关项目的标准。

迈克·威廉姆森(Mike Williamson)对此写了一篇很好的博客文章: https://mikewilliamson.wordpress.com/2015/07/16/data-modeling-with-arangodb/

他认为,从单个顶点获得大量边是很慢的,而来自流行 Tag 顶点的边数就是这种情况。