SyntaxHighlighter

2012年11月3日土曜日

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

【NDB プロパティについて】


NDBのエンティティはプロパティの定義ができる。
エンティティはデータを保持するために用いるPythonのクラスと似ている。
それらはデータベースのスキーマにも似ている。

・最初に
典型的なアプリケーションはデータモデルをModelクラスを継承したクラスにプロパティを定義する。

上記はusername, userid,emailがAccountのプロパティとなっている。
いくつか違う型のプロパティを用いているが、手軽に日付、時間を表す事が出来て、自動更新機能も付いるプロパティもある。
アプリケーションはプロパティに特別な振る舞いを指定でき、それらは簡易な検証や、デフォルト値設定、インデックスの変更などができる。
モデルは複合プロパティを持つ事が出来る。また、リストのようなRepeated propertiesも設定できる。構造体プロパティはオブジェクトのように、読み込み専用計算プロパティは関数により定義できる。プロパティに多方面の他のプロパティを定義することが簡単にできる。Expandoモデルは動的にプロパティを設定できる。

・プロパティの型

NDBは以下のプロパティの型をサポートしている。

IntegerProperty:64-bitのInteger型
FloatProperty:倍精度のfoating-point numberの型
BooleanProperty:Boolean値
StringProperty:Unicodeの文字列で500文字以内。インデックスされる。
TextProperty:Unicodeの文字列で長さに制限はないが、インデックスできない。
BlobProperty:byte配列を格納する。もし500文字以内の文字列であれば、インデックスされる。インデックスしないのであれば、長さに制限はない。圧縮もできる。
DateTimeProperty:日付や時間
DateProperty:日付
TimeProperty:時間
GeoPtProperty:位置情報。これはbdb.GeoPtオブジェクトでlatとlonをどちらもfloatで持っている。ndb.GeoPt(52.34, 4.88)やndb.GeoPt("52.37, 4.88")などで生成できる。
KeyProperty:DatastoreのKey、kind="カインド"を指定すれば、キーの割当にいつもカインドを示すことが必須にできる。それは文字列かModelのサブクラスであろう。
BlobKeyProperty:古いdb API(BlobReferenceProperty)に対応しているがプロパティの値はBlobKeyの代わりにBlobInfoとなる。BlobInfoは使用しているBlobInfo(blobkey)から構築できる。
UserProperty:ユーザーのプロパティ
StructuredProperty:値により内部的に別のモデルのカインドを含む
LocalStructuredProperty:StructuredPropertyに似ているが、ディスク上では不透明なblobとして表現され、インデックスはされない。圧縮可能。
JsonProperty:Pythonのjsonモジュールを使ってシリアライズしたオブジェクトを設定できる。JSONシリアライズしてblobとしてdatastoreに格納される。デフォルトでインデックスはされない。圧縮可能。
PickleProperty:pickleプロトコルを使ってシリアライズされたPythonのオブジェクトを設定できる。pickleシリアライズされたデータをblobとしてdatastoreへ格納する。デフォルトでインデックスはされない。圧縮可能。
GenericProperty:汎用的な値で、主にExpandoクラスで使われる。ただし、明示的に使用可能な型はint,long,float,bool,str,unicode,datetime,Key,BlobKey,GeoPt,User,Noneとなっている。
ComputedProperty:UDFによって他のプロパティより計算された値を設定できる。

いくつかのプロパティはオプションの引数のcompressedを使用する事ができる。もし、プロパティがcompressed=Trueで設定されていた場合はデータはgzip圧縮されてディスク上に格納される。これにより格納容量は小さくできるが、エンコードとデコードにCPUを消費する。

・プロパティのオプション

ほとんどのプロパティの種類は、いくつかの標準的な引数をサポートしている。
第一引数はDatastoreネームを指定する任意の引数。これによってカプリケーションの観点よりもデータストアに別の名前を与える事ができる。一般的な使用方法はデータストアのスペースを減らす目的で使う。データストアは短縮されたプロパティ名を使う。以下が参考。
意味を持つ一文字など設定するとよい。


これは特にrepeated property でEntityごとに多くの値を期待している場合
に有効。
さらに、ほとんどのプロパティはkeyword argumentsをサポートしている。

詳細はArgument&Typeを参照

・Repeated Properties

どのプロパティもrepeated = Trueにするとrepeated propertyになる。
そのプロパティは基クラスのリストの値になる。
下記が参考。プロパティの値はIntegerProperty のリストとなる。
データストアはそのようなプロパティに複数の値が表示される場合がある。独立したインデックスレコードは各値の為に作成されるこれはクエリセマンティクスに影響を与える。
以下が例。

以下がEntity


tagsプロパティの検索をする場合にこのEntityはpythonとrubyどちらも満たす。

もし、repeated propertyを更新する場合は、新しいリストを割り当てるかその場で既存のリストを変更する事が出来る。新しいリストを割り当てた場合は即時に型チェックが行われる。例えば[1,2]をart.tagsに割り当てると例外が起こる。もし、既存のリストを更新した場合は即時に型チェックは行われない。代わりにDatastoreへ書き込むときに型チェックが行われる。
データストアはrepeated propertyのリストの順番を保持する。

・日付と時間のプロパティ

日付と時間は3つのプロパティの型が有効である。
・DateProperty
・TimeProperty
・DateTimeProperty

これらの値はPythonのdatetimeモジュールのdata, time, datetime,クラスに対応する型である。3つの中で最も一般的なのはDateTimePropertyでカレンダーの日付と日付の時間を意味する。また時折便利な特別な使い方として、ちょうどの時間が必要な場合(例えば誕生日、ミーティングの時間)がある。技術的な理由としてDatePropertyとTimePropertyはDateTimePropertyのサブクラスである。ただこの継承関係に依存しない方がよい。また、この継承関係は基本になっているクラスdatetimeの継承関係とは違う。

Note:App EngineのクロックタイムはUTCで設定されている。もしPOSIX timestampsかtime tuplesに変換したデータで現在時間を使おうとする事に関係する。明白なタイムゾーンの情報をDatasotereに格納する際に与えられない。もし、ローカル時間などで現在時刻を使うときは注意が必要である。

それぞれのプロパティは下記のkeyword argmentを使う事ができる。
auto_now_add: Entityが作られた際に自動的に現在時刻が設定される。
auto_now: Entityが更新された際に自動的に現在時刻が設定される。
これらのオプションはrepeated=Trueと複合することができない。どちらもデフォルト値はFalseでもし両方Trueにした場合はauto_nowが優先される。auto_now_add=Trueは上書きすることが出来るが、auto_now=Trueはできない。自動的な値はEntityが書き込まれるまで設定されない。これらのオプションはdynamic defaultsを提供していない。

・Structured プロパティ

構造化されたプロパティを設定する事が出来る。以下が例である。
Contactモデルクラスは住所をリストで持っている。

以下のような一つのEntityが作成される。


Entityを読み直すとContactエンティティを正確に再構築する。しかし、Adressインスタンスはモデルクラスと同じ構文を使用して定義されているが、Entityではない。これらはKeyを持っていない。Contactエンティティから独立して取得することができない。個々のフィールドへのクエリーとしてならアプリケーションで可能である。(Structured プロパティへのフィルタリングを参照)adress.type, address.streedとaddress.cityはDatastoreの観点では並行だが、NDBはこの側面を隠している。NDBでは関連するAdressインスタンスのリストとして構築している。
プロパティオプションを指定する事も出来る(indexedなど)この場合は、第二引数にDatastoreの名前を指定している。
もしStruectureプロパティへのクエリが必要ない場合はLocalStructuredPropertyを代わりに使用する事が出来る。Pythonコードとしては同じであるが、データストアは各AdressのBlobを見ている。例で作成したEntityは以下のようになる。

Entityは正しく読み戻される。このタイプのプロパティは常にインデックスは無いので、Adressをクエリで検索することは出来ない。

・Computed プロパティ

Computedプロパティは読み込み専用で、アプリケーションが提供する関数で計算した結果を設定することが出来る。計算された値はクエリとDatastoreビュアーの為に書き込まれるが、格納された値はDatastoreから読み戻された際は無視される。値は、関数が呼びだされた際に再計算される。以下が例。

格納されたEntityのプロパティの値は以下のとおり

もしnameをNickieに変更した場合にname_lowerはnickieを返す。

Note:もしクエリーで計算した値を使いたい場合は、ComputedPropertyを使う。もし派生バージョンのPythonコードを使いたい場合はregular methodを定義するか@propertyを使うとよい。

・ProtoRPC Message プロパティ

ProtoRPC API は 構造データの為にMessageオブジェクトを使用する。これらはRPCリクエスト、レスポンス、等を表現できる。NDBはMessageオブジェクトをEntityのプロパティとして定義できる。Messageサブクラスを定義すると仮定すると、

NDBのmsgprop APIを使用してDatastoreへEntityのプロパティとして格納できる。


もしクエリで検索したい場合はインデックスする必要がある。MessagePropertyへのindexed_fieldsを指定する事が出来る。
MessagePropertyは通常のプロパティオプションの全てはサポートしていない。
以下がサポートしているオプション
・name
・repeated
・required
・default
・choices
・validator
・verbose_name

Message プロパティはそれ自体にindexを使う事は出来ない。(フィールド名をしていすることで、indexできる)

ネストしたmessageも使用できる。


MessagePropertyは特別なオプションprotocolを指定できる。これはdatastoreへmessageオブジェクトをどのようにシリアライズして格納するかを指定できる。protocolの値はprotorpc.remote.Protocolsクラスの名前を使用できる。サポートするprotocolはprotobufとprotojsonでデフォルトはprotobuf
msgpropはEnumPropertyも定義できる。このプロパティはprotorpc.messages.Enumの値をエンティティとして格納できる。以下が例。


EnumPropertyはintegerとして格納される。事実としてEnumPropertyはIntegerPropertyのサブクラスである。また、既に格納されているEnumの名前を変更することは出来るが、再度採番することはできない。

EnumPropertyは以下のオプションをサポートしている。
・name
・indexed
・repeated
・required
・default
・choices
・validator
・verbose_name

今回はプロパティについて紹介した。
構造化されたプロパティをそのまま格納できるのは便利だと思った。
実は実際に使った事がないので、近いうちに使ってみたい。
次回は、プロパティのサブクラスについて。

0 件のコメント:

コメントを投稿