版本控制
每当您重构数据模型时,就会创建该模型的新版本。出于审计目的、趋势分析等需求,跟踪数据结构的变更或展示当前与过去的值是非常有价值的。本页面概述了为了跟踪随时间变化的数据而可以采用的不同建模方式。
实体版本控制
您可以通过对相关实体进行版本控制来跟踪数据变化。当您需要满足以下需求时,此策略非常有用:
-
在图中访问特定实体(例如节点)的多个版本(例如产品在不同时间所使用的不同名称)。
-
仅检索最新版本(例如产品的当前名称)。
使用实体版本控制时:
-
实体
Product通过显式关系链接到其不同的版本。 -
实体
Product是不可变的。只有存储在不同版本(State节点)中的属性会发生变化。 -
LATEST关系将实体Product链接到其最新版本(State),即版本 2(V2)。
基于时间的实体版本控制
实体版本控制的一种变体是基于时间的方法。当您需要进行以下操作时,它非常有用:
-
图快照:通过检索图中特定时间点所有有效的元素(节点和关系)来获取快照(例如,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关系链接到下一个元素。
时间轴树
正如建模设计中所述,时间轴树是一种常见的建模设计。当您想要跟踪变更时,它是一种有用的策略。在此示例中,时间轴结构从年份延伸到日期,而非时间数据节点是图中包含重要数据片段的节点。
查询示例
如果您想查找给定时间段内发生的所有购买(例如 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