NDB/Google App Engine的简单版本/历史

4
我希望创建一个系统以跟踪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。


你有没有考虑过简单地使用类似Git的模型,并将其调整为适合自己的目的? - Nick Johnson
我很好奇你是否找到了解决办法,因为我也有类似的问题。 - Totem
1个回答

2
一些想法:
  • 你需要为版本创建单调递增的ID,以便可以对Version实体进行范围查询。这可能意味着你需要将所有历史数据放在与文档相同的实体组中,并在文档实体或同一组中的单独实体中保留最新版本ID。如果你需要系统范围的单调递增ID(例如将多个不同组中的实体的更改关联或排序),则需要了解分片计数器和跨组事务。

  • 如果空间是一个问题,你将存储差异,我不明白为什么要用后台任务将完整版本减少到差异,而不是在更新时就进行减少。如果空间不是一个很大的问题,并且一个主要功能是能够区分任意两个版本,则只需存储完整数据可能会更容易,这样差异的成本就不会与中间版本的数量成比例(或者所有版本,如果你的差异在历史版本之间)。假设你不想对过去版本的属性执行查询,那么你可以通过紧凑的形式序列化旧实体,并将其存储在非索引的blob属性中来节省空间。 (如果使用差异,你也可以这样存储每个差异吗?)你还可以在每n个版本里保存重要提交的完整文档,这样两个历史版本之间的差异最多需要2n个版本来计算。

  • 从你的描述中可以看出,你更希望MyDoc是对Version实体的引用,Version实体包含了最新的数据。也许让MyDoc包含最新数据(并使用MyDoc键等进行索引),然后更新只会创建包含以前数据的Version(差异或完整)会更容易。

  • 不要忘记适应删除操作。也许MyDoc消失了(因此不会出现在键和属性查询中),并且父路径的最新版本包含完整的最后已知文档。

(这只是我想到的。我为我正在开发的一个CMS考虑过这些问题,但还没有实现。)


许多版本控制系统没有单调递增的ID。而且你不能使用分片计数器来生成单调递增的ID。 - Nick Johnson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接