Cloud Datastore でのデータの保存

Python ゲストブック コード チュートリアルのこの部分では、構造化データを Cloud Datastore に格納する方法を説明します。App Engine と Cloud Datastore を使用すれば、データの配布、複製、負荷分散のいずれもが単純な API で実現されます。加えて、強力なクエリエンジンとトランザクションも使用できます。

このページは複数のページからなるチュートリアルの一部です。チュートリアルを最初から始めて設定手順を確認するには、ゲストブックの作成に移動してください。

送信されたメッセージの保存

データは、Cloud Datastore 内のエンティティと呼ばれるオブジェクトに書き込まれます。各エンティティには、それを一意に識別するキーが割り当てられます。エンティティは、オプションで、別のエンティティを「親」として指定できます。最初のエンティティは、親エンティティの「子」になります。こうして、データストア内のエンティティは、ファイル システムのディレクトリ構造と同じような階層構造空間を形成します。詳細については、強整合性に対応するデータ構造をご覧ください。

App Engine には Python 用のデータ モデリング API が付属しています。データ モデリング API を使用するために、サンプルアプリは google.appengine.ext.ndb モジュールをインポートします。各メッセージには投稿者の名前、メッセージの内容、投稿日時が含まれています。アプリではメッセージが時系列で表示されます。次のコードは、データモデルを定義します。

class Author(ndb.Model):
    """Sub model for representing an author."""
    identity = ndb.StringProperty(indexed=False)
    email = ndb.StringProperty(indexed=False)

class Greeting(ndb.Model):
    """A main model for representing an individual Guestbook entry."""
    author = ndb.StructuredProperty(Author)
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

このコードは、次の 3 つのプロパティで Greeting モデルを定義します。値がメールアドレスと投稿者の ID を含む Author オブジェクトである author、値が文字列である content、値が datetime.datetime である date です。

パラメータで詳細な動作を構成できるプロパティ コンストラクタもあります。ndb.StringProperty コンストラクタに indexed=False パラメータを渡すと、このプロパティの値にはインデックスが付けられません。これにより、アプリでそのプロパティがクエリに使用されなくなるため、不要な書き込みをしなくて済みます。ndb.DateTimeProperty コンストラクタに auto_now_add=True パラメータを渡すと、アプリケーションによって値が提供されない場合に、新しいオブジェクトにその作成時の datetime スタンプが自動的に付与されるようにモデルが構成されます。プロパティ タイプとそれらのオプションの完全なリストについては、NDB プロパティをご覧ください。

アプリケーションでは、新しい Greeting オブジェクトを作成して Cloud Datastore に配置するためにデータモデルが使用されます。Guestbook ハンドラが新しいメッセージを作成してそれらをデータストアに保存します。

class Guestbook(webapp2.RequestHandler):

    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each
        # Greeting is in the same entity group. Queries across the
        # single entity group will be consistent. However, the write
        # rate to a single entity group should be limited to
        # ~1/second.
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = Author(
                    identity=users.get_current_user().user_id(),
                    email=users.get_current_user().email())

        greeting.content = self.request.get('content')
        greeting.put()

        query_params = {'guestbook_name': guestbook_name}
        self.redirect('/?' + urllib.urlencode(query_params))

この Guestbook ハンドラは、新しい Greeting オブジェクトを作成してから、その author プロパティと content プロパティをユーザーが投稿したデータに設定します。Greeting の親は Guestbook エンティティです。別のエンティティの親に設定する Guestbook エンティティを作成する必要はありません。この例では、トランザクションと整合性を目的としたプレースホルダとして親を使用します。詳細については、トランザクション ページをご覧ください。共通の祖先を共有するオブジェクトは、同じエンティティ グループに属しています。このコードでは date プロパティが設定されないため、date は自動的に auto_now_add=True を使用して現在に設定されます。

最後に、greeting.put() によって新しいオブジェクトがデータストアに保存されます。このオブジェクトをクエリから取得した場合は、put() によって既存のオブジェクトが更新されます。このオブジェクトはモデル コンストラクタを使用して作成されているため、put() によって新しいオブジェクトがデータストアに追加されます。

Cloud Datastore におけるクエリはエンティティ グループ内でのみ強整合性を示すため、コードでは、すべてのメッセージに共通する親を設定することにより、1 つのブック内のすべてのメッセージが同じエンティティ グループに割り当てられます。したがって、メッセージは常に書き込みの直後にユーザーに表示されます。ただし、同じエンティティ グループに書き込める頻度は毎秒 1 回に制限されます。実際のアプリケーションを設計するときは、この点を考慮する必要があります。Memcache などのサービスを使用すると、書き込み後に複数エンティティ グループを横断してクエリを実行した場合に、ユーザーに新しい結果が表示されなくなる可能性を低減できます。

送信されたメッセージの取得

Cloud Datastore は、データモデル用の高度なクエリエンジンを備えています。Cloud Datastore は従来型のリレーショナル データベースではないため、クエリを指定する際に SQL は使用しません。その代わりに、Datastore クエリを使用するか、GQL という SQL に似たクエリ言語を使用して、データのクエリを行います。Cloud Datastore のすべてのクエリ機能を活用するには、GQL によるクエリを使用することをおすすめします。

MainPage ハンドラは、過去に送信されたメッセージを取得して表示します。greetings_query.fetch(10) を呼び出すとクエリが実行されます。

Cloud Datastore のインデックスの詳細

Cloud Datastore 内のすべてのクエリが 1 つ以上のインデックスから計算されます。このインデックスは、順序付けられたプロパティ値をエンティティ キーにマップするテーブルです。アプリケーションのデータストアの規模にかかわらず App Engine がすばやく結果を返すことができるのは、この仕組みによります。多くのクエリは組み込みのインデックスから計算できますが、より複雑なクエリの場合は、Cloud Datastore に「カスタム インデックス」が必要になります。カスタム インデックスを使用しない場合は、Cloud Datastore でこれらのクエリを効率的に実行できません。

たとえば、ゲストブック アプリケーションは、上位クエリと並べ替え順序を使用して、ゲストブックでフィルタリングし、日付順に並べ替えます。そのためには、アプリケーションの index.yaml ファイルでカスタム インデックスを指定する必要があります。このファイルは、手動で編集することも、アプリケーションでローカルにクエリを実行することで自動的に処理することもできます。index.yaml でインデックスを定義してから、アプリケーションをデプロイすると、カスタム インデックス情報もデプロイされます。

index.yaml 内のクエリの定義は次のようになります。

indexes:
- kind: Greeting
  ancestor: yes
  properties:
  - name: date
    direction: desc

Cloud Datastore インデックスの詳細については、データストア インデックス ページをご覧ください。index.yaml ファイルの正しい指定方法については、Python データストアのインデックスの構成をご覧ください。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Python 2 の App Engine スタンダード環境