Google App Engineのキーバリューストア(DataStore)の特徴はSQLライクな構文による検索と、インデックスを使える事です。といっても、一般的なDBMSほどの機能を提供してくれるわけではありません。Google App EngineのDataStoreの特徴を踏まえて上手に使いましょう。
インデックスの制限
DataStoreのインデックスはstlのmapと同様の構造になっており、ソートの為に使用するインデックスと検索のために使用するインデックスは共有されているようです。そのために様々な制限が加わります。
制約1
検索条件で不等号を指定した場合には、検索条件と異なる並べ替えの指定をできません。where区で指定したフィールドは、order by区でも指定する必要があります。
×・・・WHERE col1 > 1 ORDER BY col2
○・・・WHERE col1 > 1 ORDER BY col1, col2
制約2
複数の不等号による比較条件を持つクエリーを実行できません。
×・・・WHERE col1 >= 10 AND col2 > 10
制約3
OR演算子がありません。代わりにIN演算子が用意されていなすが、異なるフィールドを指定したOR検索は出来ません。
制約4
ひとつのアプリケーションで作成できるインデックスの数は 個に制限されている。制限3と合わせて、無闇にインデックスを作成すると規模の大きなアプリケーションでは制約に引っかかる可能性があります。
制約5
セッション分離をサポートしません。一般的なDBMSは他のセッションから更新が行われても、他のセッションは新しいセッションを始めるまで影響を受けませんが、DataStoreでは即時に反映されます。
これらの制約を踏まえて如何にして旨く活用していくかが問題になります。
DataStoreを使いこなすには?
施策1 スクリーニングに留める
GQLによる検索はスクリーニングに留めます。例えば特定条件に一致するデータを日付順で取得したい場合には、日付によるソートのみをGQLで行い、条件に一致するか否かはコードで記述します。
施策2 頁番号フィールドを作る
大量のデータをすべて読み出しながら処理を行う場合には、一度に全てのレコードを読み出すことは出来ません。先頭レコードと読み出すレコード数を指定して、数百レコードずつ読み出して処理を行うことになります。この場合、処理中に他のプロセスからレコードの追加、削除が行われると、同じ行を二回処理したり、処理されないレコードが発生する恐れがあります。
これを防ぐために頁番号フィールドを作成して、数百レコード格納する毎に頁番号を繰り上げるようにします。読み出すときには、頁番号を指定することで一度に処理可能なレコード数を読み出します。頁番号を繰り上げながら順次読み出すことで、途中でレコードが追加されても最後まで読み出すことが出来ます。
施策3 検索条件、ソート条件の分離
検索条件やソート条件を別のエンティティに分離します。それぞれのエンティティ毎に検索・ソートを行うことで、全体として目的の結果を得ます。
例えば会員情報を格納したエンティティから年齢18歳以上の人を都道府県毎にソートして取得したい場合を考えてみます。都道府県を格納したエンティティからソートした状態でレコードを読み出します。次に会員情報に対して県名と年齢を検索条件として読み出します。ソートされた県名順にデータを読み出していくので、結果的に件名でソートされた18歳以上の会員一覧を得られます。
このように複数回の検索に分離することで望んだ結果を得ます。
施策4 検索を使わないように設計する
実は王道かもしれません。GQLに頼らなくても望みのデータを取得出来るようにエンティティを設計します。
この話は、別の記事にて。