2012-08-01 31 views
1

我刚刚完成了使用mapreduce为GAE的数据存储上执行模式升级设置基础。我们正在使用NDB,并且很多或我们的模型都会使用DateTimeProperty的auto_now关键字选项来设置last_modified属性。Schema升级和last_modified属性(GAE和NDB)

last_modified = ndb.DateTimeProperty(auto_now=True) 

当然,在运行更新实体的mapreduce作业时,last_modified属性也会更新,这实际上并不是我们想要的。

def upgrade_entity(entity): 
    # modify entity 
    yield op.db.Put(entity) 

根据文档,您可以覆盖auto_now_add设置属性的值,但不会覆盖auto_now。

我现在认为可能有其他情况,我们不希望last_modified属性也被更新。

那么,有什么办法来保存实体的last_modified值,或者我们添加另一个属性或替换这些属性与我们可以控制,只需手动设置值?


OK,这样的共识似乎是,我应该能够定义一个仅用于映射精简代码,而不是面向代码的用户模型的替代版本(我非常想避免关闭该站点以进行模式升级),但是我一直无法得到这个工作。

通过以下设置,面向用户的代码能够正常工作(更新last_modifed),直到我运行也正常工作的mapreduce(不会更新last_modified)。运行mapreduce的用户面临的代码不再更新LAST_MODIFIED ..

models.py

class MyModel(ndb.Model): 
    # model used by user facing code 
    last_modified = ndb.DateTimeProperty(auto_now=True) 

upgrade.py

class MyTmpModel(ndb.Model): 
    # model used by mapreduce code 
    @classmethod 
    def _get_kind(cls): 
     return 'MyModel' 
    last_modified = ndb.DateTimeProperty(auto_now=False) 

def upgrade_model(entity): 
    # mapper function 
    # modify entity 
    yield op.db.Put(entity)  

mapreduce.yaml

mapreduce: 
- name: Upgrade Model 
    mapper: 
    input_reader: mapreduce.input_readers.DatastoreInputReader 
    handler: upgrade.upgrade_model 
    params: 
    - name: entity_kind 
     default: upgrade.MyTmpModel 


确定后,我要把我的问题放在这里在我一直在dev_server中测试它,以及与真正的gae服务器相比,在那里运行的方式有所不同。我的结论是,在dev_server所有的代码在同一个进程中运行,并在不同的模型版本不沿着..从NDB模型文档使用:

的应用程序不应该使用相同的定义两个模型类善良,即使他们生活在不同的模块中。一个应用程序的种类被认为是全局的“命名空间”。

我以为我可以依靠的事实,真正的GAE服务器上的MapReduce代码将在单独的情况下运行,这些版本冲突不会发生,也不会影响用户面临服务器实例使上面的设置应该按预期工作。

感谢Tim & Guido为您提供帮助。

欢呼声,

Ĵ

+0

您可以添加auto_now未设置为True的版本,并针对该版本运行您的mapreduce。它不会为您提供您想要的细粒度控制,但可能是您的模式迁移过程中最简单的方法。蒂姆,感谢 – 2012-08-01 06:25:46

+0

。你让它听起来很简单,所以也许它是......而且这也应该适用于使模型成为Expando的子类以去除属性..所以现在我想我可以在某处定义模型的临时版本并使用它在mapreduce配置中,只要它与我的实际模型具有相同的类名称? (了解更多关于Python每天如何工作的信息..以及GAE和NDB ..) – lecstor 2012-08-01 06:45:48

+0

hmm ..好的,为了记录,在我的mapper函数中定义我的“临时”版本的模型,并在mapreduce配置中引用它,但后来当我进入我的应用程序并修改了实体时,last_modified属性没有更新,因此它似乎在模型的“临时”版本中也覆盖了我的真实版本。不幸的是,这意味着任何使用该应用程序的人都将使用该模型的“临时”版本。 – lecstor 2012-08-01 11:50:34

回答

1

解决的办法是设置auto_now =假在地图上所有的模型定义/减少代码。

我与出错的机会最小这样的建议:

定义一个全局变量,可以是真或使用为模型中定义的所有auto_now设置为False。然后,您必须仅更改所有型号的一条线,将其从True更改为False。您甚至可以根据某个环境变量自动计算值。

+0

。那么我可以在哪里设置一个env变量来区分面向用户的代码和mapreduce代码?计算何时何地完成? (我已经添加了我的tmp模型尝试到我原来的问题) – lecstor 2012-08-01 22:35:59

+0

再次感谢,我已经添加了我的结论到原来的问题。 – lecstor 2012-08-02 00:56:28

+2

其实我认为你使用相同*版本*的应用程序你的地图/减少至于常规的代码?不要那样做,他们会混在一起。相反,将您的mapreduce作业部署为不同的版本(只需编辑app.yaml)。然后你可以检查环境中的版本,例如os.getenv('CURRENT_VERSION_ID')。split('。')[0] – 2012-08-03 14:58:03