SyntaxHighlighter

2012年10月1日月曜日

Google App Engine Python NDB を使ってみた。(1)


今回は何回かにわたってGoogleAppEngineNDBという
DatastoreのAPIを紹介する。
というかリファレンスに載っているExampleとともに
自分の理解のために使ってみようと思う。

Python NDB の概要


NDB APIは通常のDatastoreのアクセスモジュールと使い方はほとんど変わらないが、
いくつかの便利な機能が追加されている。
自動でキャッシュを使ったり、クエリーやトランザクションなど構造化された
データレコードを格納する事に適している。

NDBの基本的な使い方


●始めに
NDBは通常のDatastoreのオブジェクト同様に、一つまたは複数のプロパティーを持つエンティティーとしてデータを格納する。
NDBは一つのトランザクションで複数の処理をまとめることが出来る。
もし処理が失敗したらロールバックされる。
これらは複数のユーザーが同時にアクセスしたり操作したりできるとても有用なものである。
NDBMemcacheサービスを使用してキャッシュを行う。
これは頻繁に同じエンティティーにアクセスする際に有用であり、高速で処理が行える。
NDBも通常のDatastoreと同様modelを定義する。
modelとはデータベースのスキーマのようなものである。
基礎となるDatastoreがこれらのデータオブジェクトを格納する方法は非常に柔軟である。
例えば、二つの異なるプロパティを持つエンティティーを同じカインドに格納する事ができる。NDBは型のチェックを行うが、それは必須ではない。
それぞれのエンティティはキーを持っていてそれらはアプリケーション内で一意である。
キーは親を持つ事ができて親子関係を作る事ができる。親の無いキーはルートと呼ぶ。
キーが同じルートを持つエンティティはエンティティグループまたはグループを形成することができる。
エンティティが別のグループに属している場合は、
これらのエンティティへの変更は、しばしば "順不同"が発生するように見えるかもしれない。
エンティティは、アプリケーションのセマンティクスとは無関係である場合、それは問題が、
それらを作成するときに、いくつかのエンティティの変更が一貫していなければならない場合、それらを同じグループの一部にする必要がある。

テストコードで実際に動作させてみた。

・データの格納と抽出


ここでは、カインドBookに一件エンティティ格納している。
格納した後にFetchを行って、抽出されたエンティティの検証を行っている。
Greetingオブジェクトのputメソッドを呼び出して格納している。
新たにGreetingオブジェクトを格納する場合は、すべて同じBookのエンティティグループ
となる。(親が同じ)すなわち、先祖クエリを使用している。
次にエンティティの抽出を行っている。
一般的にNDBのクエリーはカインドでエンティティーをフィルタする。
このサンプルではGreetingエンティティクラスにquery_bookというクラスメソッドを定義することにより、エンティティを返却する為のクエリーを生成している。
上記例では親のキーを指定することにより抽出するクエリーを実行している。
すべてのクエリは、インデックス、希望の順番でクエリの結果を含むテーブルを使用している。基礎となるDatastoreは、自動的にシンプルなインデックス(1つのプロパティのみを使用したインデックス)を維持する。
またこれらはindex.yamlで定義したインデックスも使用できる。

実行結果

NDBのデータ書き込みについて
コミット段階では、基礎となるDatastoreサービスでは、変更をコミットする。
NDBは影響を受けるエンティティ/エンティティのそのキャッシュを無効にする。
したがって将来の(およびキャッシュ)からではなく、キャッシュから古い値を読んでの基礎となるデータストアを読み込む。
そして基礎となるデータストアは、変更を適用する。それがグローバルクエリには表示され、最終的には一貫性の変化を読み取ることができる。(結果整合性)

データ(例えば、put()の)書き込みのNDB関数はキャッシュ無効化した後に返し、適用は非同期で行われる。

Commitフェーズ中に障害が発生した場合、自動再試行がありますが、障害が引き続き発生する場合は、アプリケーションが例外を受け取る。
コミット段階が成功して適用に障害が発生した場合、次のいずれかが発生したときに、適用フェーズは最後までロールフォワードされる。

・データストアは適用が不完全に終わったジョブを継続的に一掃し、エンティティへの変更をまだ受け取っていないインデックスとエンティティに対して、書き込みをロール フォワードします。
・次回このエンティティ グループでトランザクションを書き込むか、トランザクションを開始する際に、データストアは最初にロール フォワードを行い、ログ内のデータに基づいて、このコミット済みで未適用の書き込みの適用を完了します。

このような振る舞いはアプリケーションにどのように影響するかというと、
変化は完全に数百ミリ秒かそこらのNDB関数が戻った後に、基礎となるデータストアに適用されない場合がある。(結果整合性)
つまり変更が適用されている間にクエリを発行すると矛盾した状態が表示される場合がありる。書き込みのタイミングとクエリの詳細については、アプリケーションEngine.readsのトランザクション分離を参照とのこと。

●Django
DjangoでもNDBは使える。

●QuotaとLimits
最大エンティティーサイズ:1 megabyte
最大トランザクションサイズ:10 megabytes
1つのエンティティへの最大インデックス数:20000
1つのエンティティへの複合インデックス数:2 megabytes

今回は、NDBの概要について紹介してみた。
次回はNDBのエンティティとKeyについて紹介する予定。

0 件のコメント:

コメントを投稿