1

如果搜索API操作可以成爲數據存儲事務的一部分,那麼從文檔中不太清楚。因此,我們可以期待我們期望從事務中的數據存儲操作獲得相同的ACID屬性。在這方面是一個類似於實體的文檔?App Engine搜索API是否支持事務?

從這段視頻看來,他們是交易的一部分: http://www.youtube.com/watch?v=7B7FyU9wW8Y&list=FLcBSmKKUXoPd5yFneNFDv4A#t=1952

如果沒有,我們如何保持大面積推廣應用的一致性?

回答

2

爲您的搜索文檔建立索引不是事務性的,但是什麼是事務性的推遲了以後要運行的任務。

您可以檢查,如果你是在一個事務中與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()) 
+0

該文章非常有幫助。 – Micro

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 
+0

謝謝布賴恩。我感謝你實現了「post_put_hook」,但我沒有看到任何代碼中的事務或ACID屬性的例子。知道如何處理在文檔創建過程中提到的錯誤會更有趣? – Jens