版本控制

每当您重构数据模型时,就会创建该模型的新版本。出于审计目的、趋势分析等需求,跟踪数据结构的变更或展示当前与过去的值是非常有价值的。本页面概述了为了跟踪随时间变化的数据而可以采用的不同建模方式。

实体版本控制

您可以通过对相关实体进行版本控制来跟踪数据变化。当您需要满足以下需求时,此策略非常有用:

  • 在图中访问特定实体(例如节点)的多个版本(例如产品在不同时间所使用的不同名称)。

  • 仅检索最新版本(例如产品的当前名称)。

使用实体版本控制时:

  • 实体 Product 通过显式关系链接到其不同的版本。

  • 实体 Product 是不可变的。只有存储在不同版本(State 节点)中的属性会发生变化。

  • LATEST 关系将实体 Product 链接到其最新版本(State),即版本 2(V2)。

优缺点

优点 缺点

在建模、查询和维护方面较为简单。

更新节点需要删除 LATEST 关系,并在实体与其最新版本之间创建新的关系。

对于最终用户而言,无需任何转换即可直观理解。

如果不结合其他版本控制模式,其功能可能受限,因为如果不是要检索最新版本,很难定位所需的特定版本。

查询示例

以下是在实体版本控制策略下常用查询的示例:

获取 ID 为 '1' 的 Product 的版本 2 的名称
MATCH (:Product {id:1})-[:V2]->(s:State)
RETURN s.name
获取 ID 为 '1' 的 Product 的最新版本名称
MATCH (:Product {id:1})-[:LATEST]->(s:State)
RETURN s.name

基于时间的实体版本控制

实体版本控制的一种变体是基于时间的方法。当您需要进行以下操作时,它非常有用:

  • 图快照:通过检索图中特定时间点所有有效的元素(节点和关系)来获取快照(例如,2023年6月12日周一有哪些产品可用)。

  • 图差异:通过比较两个不同时间戳的图快照(例如,哪些节点是新增的,哪些被删除了,哪些保持不变)。

  • 时态遍历:仅遍历图中特定时间点有效的元素(节点或关系),以找到连接基于时间事件的关系的时间序列(例如,以站点为节点、行程关系为边的共享单车图)。

  • 图历史:通过建模数据变更的历史记录。

使用基于时间的实体版本控制时:

  • 每个元素都有专门的 validFrom(生效起始)/validTo(生效结束)时间属性。

  • 节点仅当其有效时间跨度重叠时才能建立关系。

  • 可能会出现信息冗余。

  • 可以使用完整的图历史记录。

优缺点

优点 缺点

每个元素都有定义明确的有效时间间隔。

如果节点的状态发生变化,则必须复制该节点,并为其分配一个新的有效时间间隔。

状态绑定到特定元素(不需要额外的关系)。

更新节点需要创建连接到新节点/状态的新关系,并为该关系分配一个新的有效间隔。

可以对所有元素(或仅在特定时间有效的元素)进行聚合。

数据冗余不可避免。

查询示例

以下是在基于时间的实体版本控制策略下常用查询的示例:

获取 Product “电饭煲”的当前价格
MATCH (p:Product)
WHERE p.name = “Rice Cooker” AND p.validTo = ∞
RETURN p.price
获取 Product “电饭煲”在 11 月份的价格
MATCH (p:Product)
WHERE p.name = “Rice Cooker”
AND datetime(p.validFrom) <= datetime(“November”) <= datetime(p.validTo)
RETURN p.price
获取当前的产品目录及价格
MATCH ()-[r:HAS_PRODUCT]->(p)
WHERE r.validTo = ∞
RETURN p.name, p.price

链表

链表是另一种建模策略,当对象的顺序很重要时非常有用。

链表在以下情况下很有用:

  • 需要关注事件的顺序,例如获取银行账户中交易执行的顺序。

  • 根据元素之间的关系,您需要列表中的前一个或后一个元素(例如播放列表中的下一首歌曲,或撤销文本文档中的某项操作)。

使用链表时:

  • 实体 Product 链接到序列的第一个元素,也可以链接到最后一个元素。

  • 实体版本控制一样,实体 Product 在此处也是不可变的。

  • 序列中的每个元素通过 NEXT 关系链接到下一个元素。

优缺点

优点 缺点

通过使用关系来获取下一个/上一个元素,效率很高。

如果不使用其他版本控制模式,则局限于非常特定的用例。

建模和维护简单。

难以查找非首尾的特定版本。

对最终用户友好,逻辑明确。

查询示例

以下是在链表版本控制策略下常用查询的示例:

获取名为“专业椅”的产品名称的下一个版本
MATCH (:State{name: “Professional chair”})-[:NEXT]->(s:State)
RETURN s.name
获取 ID 为 '1' 的产品名称的上一个版本
MATCH (:Product {id:1})-[:LAST]->(:State)<-[:NEXT]-(s:State)
RETURN s.name

时间轴树

正如建模设计中所述,时间轴树是一种常见的建模设计。当您想要跟踪变更时,它是一种有用的策略。在此示例中,时间轴结构从年份延伸到日期,而非时间数据节点是图中包含重要数据片段的节点。

查询示例

如果您想查找给定时间段内发生的所有购买(例如 2012 年 12 月的每一笔购买),可以从 2012 年开始导航时间轴树,进入 12 月,然后获取该分支下连接的所有叶子节点(没有后代的节点)。

MATCH (root:Timeline)-[:IN_YEAR]->(year:Year {value:2012})-[:IN_MONTH]->(month:Month {value:12})
WITH month
MATCH (month)-[:ON_DAY]->(day)
MATCH (purchase:Purchase)-[:OCCURRED]->(day)
RETURN purchase

组合方法

一些复杂的用例需要结合上述一种或多种建模技术,因为每种技术都有其优缺点。

正确的组合取决于具体的用例。查询时间和交易频率等因素也应一并考虑。