1

私は今ブロックされています。

問題は次のとおりです。memcache に保存されている本のリストの「ビュー」があります。新しい本を追加する場合は、本のリストを格納する memcache 変数に新しい本を追加したいと考えています。更新、削除も同様です。

「キーをフラッシュして、すべてのデータを再度収集できます」と言うことができます。しかし、結果整合性のため、新しいデータを追加してすぐにクエリを実行しても、新しいデータはまだ存在しません。

「祖先を使用して結果整合性を回避する」と言えます。ブックはルート エンティティであり、パフォーマンスのために、このレベルで祖先を使用することはお勧めできません。

したがって、データストアからの読み取りを可能な限り少なくし、memcache を同期させるという考え方です。

今私のコード、それは動作しません:

class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)

    @classmethod
    def getAll(cls):
        key = 'books'
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    @classmethod
    def addMemcache(cls, newdata):
        mylist = memcache.get('books')
        if mylist:
            mylist.insert(0, newdata)
            if not memcache.set('books', mylist):
                logging.error('Memcache set failed for key books.')

    # This saves the data comming from the form
    @classmethod
    def save(cls, **kwargs):
        book = Book(title=kwargs['title'],
                    author=kwargs['author']
               )
        # Save
        book.put()
        # Add to memcache for this key
        logging.info('Adding to Memcache for key books.')
        cls.addMemcache([book.title, book.author])
        return book

今のところ、リストの先頭に挿入するだけです。私のコードの問題は、memcache に ADD すると、ジンジャ テンプレートに「UndefinedError: 'list object' has no attribute 'title'」と表示されるため、ある種のプロパティが欠落していることです。

<td>{{ line.title[:40]|escape }}</td>

プロパティを持つオブジェクトではなくリストであるため、これは明らかです。しかし、関数 getAll() でリスト内のオブジェクトを変換し、books = list(the_query) を作成すると、なぜ機能するのでしょうか?

私の他の問題は、特定の本を変更する方法(この場合、memcacheをフラッシュして再度読み取ることができます。結果整合性の問題はないと思います)と削除する方法(2の場合にリスト内の一意の要素を識別する方法)です。本は同じ名前です)。

なにか提案を?または、memcache を同期させるという問題に対する解決策を変更する必要がありますか?

4

2 に答える 2

3

memcache の値を設定するときは、2 つの異なることを行っています。ではgetAll、キャッシュ ミスの場合memcache.set(key, books)booksは Book インスタンスのリストです。しかしaddMemcache(あなたによって呼び出され、あなたはリストのリストsave)を挿入します。ここで、内側のリストは本のタイトルと著者です。あなたが指摘したように、キャッシュから値を取得すると、それらはインスタンスとリストの混合物です.

save の行は次のようになります。

cls.addMemcache(book)

Book インスタンスを一貫してキャッシュに設定するようにします。

(また、memcache リストにaddMemcache追加する classmethod ではなく、通常のインスタンス メソッドを作成することに注意してください。また、サブクラス化する場合に備えて、saveでは、明示的に呼び出すよりもインスタンス化する方がよいでしょう。)selfclsBook

于 2013-05-22T10:24:01.703 に答える
1

@DanielRoseman の助けを借りて、問題の最終的な解決策を得ました。

他の興味のある「スタッカー」のための完全なソリューションをここに残しておきたいと思います。これには、現在機能している memcache への要素の追加、編集、および削除が含まれます。

# These classes define the data objects to store in AppEngine's data store.
class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)
    deleted = ndb.BooleanProperty(default=False)

    MEMCACHE_TIMEOUT = 0

    # Key to use in memcache for the list of all books
    @staticmethod
    def book_memkey(key='book_list'):
        return str(key)

    # Search all
    @classmethod
    def get_all(cls):
        key = cls.book_memkey()
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books, cls.MEMCACHE_TIMEOUT):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    # Save a Book and return it
    @classmethod
    def save(cls, **kwargs):
        book = cls(title=kwargs['title'],
                   author=kwargs['author']
                  )
        book.put()
        # Modify memcache for this key
        book.add_to_memcache()
        return book

    # ------------------------
    # Methods for the instance
    # ------------------------

    # Add a new element to memcache
    def add_to_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Adding to Memcache for key %s.', self.book_memkey())
            data.insert(0, self)
            if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Remove an element from memcache
    def del_from_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Removing from Memcache for key %s.', self.book_memkey())
            try:
                # Search the object in the list
                element = filter(lambda idx: idx.key == self.key, data)[0]
            except IndexError:
                pass
            else:
                logging.info('Removing element %s.', element)
                data.remove(element)
                if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                    logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Update an element on memcache
    def update_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Updating Memcache for key %s.', self.book_memkey())
            try:
                # Search the object in the list
                element = filter(lambda idx: idx.key == self.key, data)[0]
            except IndexError:
                pass
            else:
                logging.info('Updating element %s.', element)
                data[data.index(element)] = self
                if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                    logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Update a chapter
    def update(self, **kwargs):
        if 'title' in kwargs:
            self.title = kwargs['title']
        if 'author' in kwargs:
            self.author = kwargs['author']
        # Save
        self.put()
        self.update_memcache()

    # Delete de book (mark as deleted). Optionally you can assign Value=False to undelete
    def virtual_delete(self, value=True):
        self.deleted = value
        if value:
            self.del_from_memcache()
        else:
            self.add_to_memcache()
        self.put()
于 2013-05-23T06:53:15.473 に答える