SyntaxHighlighter

2012年11月18日日曜日

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

NDB Queries

アプリケーションはクエリーを使用したフィルターの基準によって指定した検索にマッチするEntityをDatastoreから検索できる。

・概要
アプリケーションはクエリーを使用したフィルターの基準によって指定した検索にマッチするEntityをDatastoreから検索できる。例えば、アプリケーションはクエリーを使ってTrackとGuestbooksを一つのguestbookから日付順に検索できるようにしたままに出来る。

いくつかのクエリーは他より更に複合にできるが、Datastoreはインデックスを事前に構築しておく必要がある。これらの事前に構築するindexはindex.yamlというconfiguration fileで定義できる。開発サーバーでは、クエリーを実行する為に必要なindexを指定していなくても動作するのだが、これは開発サーバーが自動的にindex.yamlを追加するからである。しかし実際のWebSiteでは指定していないindexが必要になると失敗する。したがって、典型的な赤井発サイクルでは、開発サーバーで新しいクエリを試して自動的に更新されたindex.yamlをWebSiteのindex.yamlとして更新する。 
また、index.yamlをアプリケーションとは別に更新できる。
もしDatastoreにたくさんのEntityが存在するとき、インデックスを作成するのに長い時間がかかる。今回の場合、新しいindexを使用するコードをアップデートかける前に、index定義を更新するのが賢明。アドミンコンソールからindex構築の状況を確認することができる。

Datastoreは一致条件に (the==operator)と比較に(<,<=,> and >= operatros)をサポートしている。複数のフィルターをANDを使用する事によって結合できるが、いくつかの制限がある(以下を参照)

さらに、APIは!=とグループのフィルタリングをORで結合できるのと、INが使える。INはPythonのinのようにlistの中で一致する要素を検査する。これらは1対1でDatastoreのオペレーションではない。従って、相対的に少し風変わりで遅い。これらは結果のストリームをインメモリでマージする実装をしている。p!=vは実装上p<v OR p>vとなっている。

制限:データストアはいくつかの制限を強制している。これらを違反すると例外を送出する原因となる。例えば、複数のプロパティーに対する不等号のフィルタリングをたくさん結合したり、異なるプロパティーでソートを行う不等号の結合フィルターは現在全て禁止されている。複数のプロパティを参照するフィルターもまた時々セカンダリーindexの設定が必要になる。

非サポート:Datastoreは一部の文字を使用する検索、大文字小文字区別なし、また全文検索はサポートしていない。これらの大文字小文字区別なしと全文検索でさえ実装するにはcomputedプロパティーを使用する。

・Propertyの値でフィルタリングする
通常は与えられたkindの全てのEntityを検索したくない。だいたいはいくつかのプロパティーに対して範囲を指定したい。
プロパティはフィルタ
ーを表すクエリーによって操作できる。例えば、useridが42をもつEntityを抽出すると以下のような表現になる。

もしuseridがAccount内で一つである事が確実であれば、useridはキーとして扱うだろう。Account.get_by_id()にした方が早いからである。
NDBは以下のオペレーションをサポートしている。
不等のフィルタリングを行う場合は、以下のような文法を使える。
これはuseridが40以上のEntityを探すクエリーとなる。

!=とINは実装上、他のオペレーションとの複合である。また、これらは少し風変わりな説明である。

複合フィルターは以下のように指定する。

この複合フィルターの引数は、useridが40以上から50未満のEntityを返すクエリーとなるが、前述のとおりDatastoreは、複数のプロパティで不等号を使用したクエリーを拒否する。

代わりに全体のクエリーフィルターを一つで表現する。多分もっと便利にクエリーを積み上げることが出来る事を見つけるであろう。
qry3は前述の例のqrtと等価である。このクエリーオブジェクトは不変であり、qry2はqry1に影響を与えず、また、qry3もqry1とqry2に影響は与えない。

・!= と IN のオペレーション
!=(不等)とIN(メンバーシップ)オペレーションはORを使った他のオペレーションとの複合である。まずは以下。
は実装上
例えば、
これは以下と等価

Note:多分驚くであろうが、このクエリーは、perlタグを含まないEntityを探すよりむしろ最低でも一つのタグがperlでない全てのエンティティーを探している。例えば次のエンティティはそのタグの一つとしてperlを持っているのみも関わらず、結果に含まれるだろう。
しかしながら、これは含まれないであろう。
perlと同じタグが含まれていないエンティティを抽出する為の方法はない。
また、INオペレーションについては、以下の表現ができる。

これはリストの値のメンバーシップを検索する。実装上は以下の通り
例は下記
以下とも等価である。

ORをしようすると重複した結果は得られない。

・Repeated Propertiesへのクエリー
Articleクラスはrepeatedプロパティへのクエリの例としても先行したセクションとして定義した。特にフィルターのように、

上記Article.tagsはrepeatedプロパティにも関わらず、一つの値を使った。すると、このプロパティはlistオブジェクトと比べることが出来なくなる。また、フィルターのように、

この場合は、tagsのプロパティーがlistの['python','ruby','php']を持っているEntityを探す事とは全く違う。これはtagsの値が['python','ruby','php']のうち最低でも一つが含まれるEntityを探す。
Noneはクエリーで検索する事が出来ない。

・ANDとORを複合して使う
ANDとORオペレーションをネストして使う事が出来る。


ORの実装の為に、ORを複合しすぎたクエリーは例外とともに失敗するであろう。これらのフィルターは下記のように、一つのレベルのANDとネストされたクエリーの最上位にあるOR
を表現する為に正規化される。この拡張は、既に!=とINに与えられた拡張とともに、ブール式のための論理和標準形を得るための標準的な規則を使用する。要するに、上記の例の正規化された形は、(非公式の表記法を使用する)


注意:
この正規化は複合の爆発の可能性がある。

・ソート順序を指定する
order()メソッドを使用してクエリーの結果の順序を指定する事が出来る。このメソッドはlist引数を受け取り、それぞれ、プロパティーのオブジェクトかまたは、それの昇順降順を指定できる。

この検索は、messageプロパティーの値で昇順にしたGreeting Entityを検索する。
連続したmessageプロパティをuseridを降順にソートした結果を返却するためには、複合のorderを呼び出せば可能である。
order()でフィルタを組み合わせたとき、データストアは、特定の組み合わせを拒否する。特に、不等号フィルタで最初の並べ替え順序を(もしあれば)を使用した場合、フィルタと同じプロパティを指定する必要がある。また、時々セカンダリインデックスを設定する必要がある。

・先祖クエリ
先祖クエリはクエリの結果を先祖から制約する。
ソート順とフィルターの複合で使用できる。
同じ先祖のEntityへの操作となるので、これは特にtransaction内で便利である。

・Queryオブジェクトの属性
Queryオブジェクトは以下のような読み込み専用の属性を持っている。
kind str None Kind name (usually the class name)
ancestor Key None Ancestor specified to query
filters Filter Node None Filter expression
orders Order None Sort orders

str()とかrepr()を呼んで内容を表示するときに表現できる。


今回はQueriesについての前半を記載した。
ここまでは特にNDBに特化した機能などはほとんどなかったが、
次回もQueriesについてだが、NDB特有のmapなど登場する予定。

0 件のコメント:

コメントを投稿