App Engine Search API是否支持交易?

时间:2014-02-11 08:33:57

标签: google-app-engine transactions google-cloud-datastore google-search-api

如果Search API操作可以成为数据存储区事务的一部分,则从文档中可以清楚地了解。因此,我们可以期望与事务中的数据存储区操作相同的ACID属性。在这方面,文件是否与实体类似?

从这段视频看,它们似乎是交易的一部分: http://www.youtube.com/watch?v=7B7FyU9wW8Y&list=FLcBSmKKUXoPd5yFneNFDv4A#t=1952

如果不是,我们如何在大规模应用中保持一致性?

2 个答案:

答案 0 :(得分:2)

索引搜索文档不是事务性的,但IS事务是将某个任务推迟到稍后运行。

您可以检查自己是否与ndb.in_transaction()进行了交易,并轻松地defer这样:

class UserModel(ndb.Model):
    ...
    def _post_put_hook(self, future):
        deferred.defer(UserModel.put_search_document,
                       self.username,
                       self.version,
                       _transactional=ndb.in_transaction())

您还需要处理重试和失败。 This excellent article有一个完整的演练和解释,包括简单的版本控制,以防止失败,重试和脏读。

以下是该文章的完整示例代码:

import logging
from google.appengine.api import search
from google.appengine.ext import ndb
from google.appengine.ext import deferred

class UserModel(ndb.model):

    username = ndb.StringProperty(required=True)
    email = ndb.StringProperty(required=True)
    version = ndb.IntegerProperty(default=0)

    @classmethod
    def put_search_document(cls, username, version):
        model = ndb.Key(cls, username).get()
        if model:
            if version < model.version:
                logging.warning('Attempting to write stale data. Ignore')
                return

            if version > model.version:
                msg = 'Attempting to write future data. Retry to await consistency.'
                logging.warning(msg)
                raise Exception(msg)

            # Versions match. Update the search document
            document = search.Document(
                doc_id = username,
                fields=[
                   search.TextField(name='username', value=model.username),
                   search.TextField(name='email', value=model.email),
                   search.TextField(name='version', value=model.version),
                   ])
            index = search.Index(name="UserIndex")
            index.put(document)

    def _pre_put_hook(self):
        self.version = self.version + 1

    def _post_put_hook(self, future):
        deferred.defer(UserModel.put_search_document,
                       self.username,
                       self.version,
                       _transactional=ndb.in_transaction())

答案 1 :(得分:0)

我不知道这是否一次可用,但它们在IO视频中显示的内容现在不可用,至少数据存储“集成”。该文档未提及“searchType”参数或“query.matches”函数。

因此,就一致性而言,我所做的只是在我的数据存储模型中添加一个post_put挂钩,并在搜索API中为该文档编制索引。我有一个索引给定实体的处理程序,在post_put挂钩中我触发了这个处理程序的任务。每当我的实体上完成put()时,我就会知道搜索索引中的文档会被更新。

当然,您必须自己管理文档创建过程中可能出现的错误,但我还没有找到比这更好的方法。

class MyModel(ndb.Model):
  fieldA = ndb.StringProperty()
  fieldB = ndb.StringProperty()

  def _post_put_hook(self, future):
    # here create document