如果搜索API操作可以成爲數據存儲事務的一部分,那麼從文檔中不太清楚。因此,我們可以期待我們期望從事務中的數據存儲操作獲得相同的ACID屬性。在這方面是一個類似於實體的文檔?App Engine搜索API是否支持事務?
從這段視頻看來,他們是交易的一部分: http://www.youtube.com/watch?v=7B7FyU9wW8Y&list=FLcBSmKKUXoPd5yFneNFDv4A#t=1952
如果沒有,我們如何保持大面積推廣應用的一致性?
如果搜索API操作可以成爲數據存儲事務的一部分,那麼從文檔中不太清楚。因此,我們可以期待我們期望從事務中的數據存儲操作獲得相同的ACID屬性。在這方面是一個類似於實體的文檔?App Engine搜索API是否支持事務?
從這段視頻看來,他們是交易的一部分: http://www.youtube.com/watch?v=7B7FyU9wW8Y&list=FLcBSmKKUXoPd5yFneNFDv4A#t=1952
如果沒有,我們如何保持大面積推廣應用的一致性?
爲您的搜索文檔建立索引不是事務性的,但是什麼是事務性的推遲了以後要運行的任務。
您可以檢查,如果你是在一個事務中與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())
好吧,我不知道這是否一次可用,但他們在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
謝謝布賴恩。我感謝你實現了「post_put_hook」,但我沒有看到任何代碼中的事務或ACID屬性的例子。知道如何處理在文檔創建過程中提到的錯誤會更有趣? – Jens
該文章非常有幫助。 – Micro