我希望创建一个系统,用于跟踪Google App Engine(Python)上ndb.Models / Expandos内容的版本(历史)。
内容可能相对较长,可能有很多版本,但版本之间的差异可能非常小。我希望其他人做过这样的事情,我想知道他们是如何做到这一点的,以及可以指导设计和原则的原则。发展。
在部署时尚不知道数据模型的属性是什么(例如“标题”,“内容”,“正文”,“日期”等),但类型是已知的(日期) ,文本等)。
我最初的想法是安排这样的事情:
from google.appengine.ext import ndb
class Version(ndb.Expando):
version_id = ndb.IntegerProperty()
# dated, etc.
# data properties are not known in advance, hence Expando
class MyDoc(ndb.Model):
head = ndb.KeyProperty(kind=Version)
instance = ndb.kind=Property(kind=Version, repeated=True)
# ^^^ may be a StructuredProperty?
算法概述如下:
每次用户保存文档时,请将所有最新数据放入新的Version
并将head
指向该实例。
此时或之后的某个时间,通过旧版本并将完整保存更改为差异(以节省空间),例如diff-match-patch。我希望每小时,每天或一些设定时间可以完全保存 - 或者设定一些差异。
加载head
非常简单。
旧版本将标记为完整保存或差异,具体取决于数据可以直接返回或从差异编译。
我相信其他人已经解决了这个问题,我很想知道有什么想法和实施。显然,有完整的版本控制系统,如Git,Mercurial和Subversion以及CVS - 但这些都是针对预期用途的过度杀伤,并且不适用于Google App Engine。
答案 0 :(得分:2)
一些想法:
您需要为版本提供单调递增的ID,因此您可以对版本实体进行范围查询。这可能意味着您将希望与文档位于同一实体组中的所有历史数据,并将最新版本ID保留在文档实体上或同一组中的单独实体中。如果您希望系统范围内单调增加ID(例如关联或订购对不同组中的多个实体所做的更改),您将需要查看分片计数器和跨组事务。
如果空间足以让您存储差异,我不明白为什么您要将完整版本减少到背景作业的差异,而不仅仅是更新。如果空间不是一个大问题,并且主要特征是能够区分两个任意版本,那么存储完整数据可能更容易,因此差异的成本与中间版本的数量不成比例(或所有版本,如果您的差异介于历史版本之间)。假设您不想对过去版本的属性执行查询,可以通过以紧凑形式序列化旧实体并将其存储在非索引blob属性中来节省空间。 (我假设这是你如何存储每个差异,如果你使用差异?)你也可以在每个修订版本的里程碑保留完整的文档,所以两个历史版本之间的差异需要最多2n个版本来计算。
根据您的描述,您似乎更喜欢将MyDoc作为对Version实体的引用,该实体将包含最顶层的数据。也许MyDoc更容易包含最前面的数据(并且其属性用MyDoc键索引等),并且更新只是创建带有先前数据的版本(diff或full)。
不要忘记容纳删除。也许MyDoc消失了(所以它不会出现在键和属性查询中),父路径的最新版本包含完整的最后一个已知文档。
(这只是我的头脑。我为这个CMS工作做了一点思考,但我还没有建立它。)