SiNBLOG

140文字に入らないことを、極稀に書くBlog

Slim3 カスタムインデックスを試してみた。

上記のやり取りを見ていて、カスタムインデックスの仕様をよく知らなかったので、調べてみた。
まず、ひが殿が指しているURLはAppEngineの公式ドキュメントですね。
Slim3にはカスタムインデックスをいじる機能は無いので、公式ドキュメントを参照してくれということでしょう。

なので、タイトルにはSlim3と入れましたが、実際にはSlim3は関係なく、GAEの話ですね。


GAEのカスタムインデックスとはなんぞや?という話です。

インデックスについては、こちらのBlogが見やすいです。
http://blog.r-learning.co.jp/archives/499

インデックスの種類はいくつかありますが、queryを利用する時に意識しそうなのは以下の2つでしょうか。

  1. シングルプロパティインデックス
  2. カスタムインデックス

シングルプロパティインデックスは、何もしなくてもModelのフィールドに基づいて自動で作られます。
検索などに使用しないので不要という場合は、以下のようにunindexed=trueとします。


public class Tweet implements Serializable {

private static final long serialVersionUID = 1L;

@Attribute(primaryKey = true)
private Key key;

@Attribute(version = true)
private Long version;

private Integer memberId;

@Attribute(unindexed = true) //内容の検索は行わないので不要
private String content;

private Date createDate = new Date();


カスタムインデックスは、シングルプロパティインデックス以外で、queryに必要なインデックスです。

簡単な例だと以下のような場合でも、カスタムインデックスが必要です。


private TweetMeta t = new TweetMeta();

public List getTweetList() {
return Datastore.query(t).sort(t.memberId.asc, t.createDate.desc).asList();
}

ソート条件として、2つの条件が指定されています。
この場合、シングルプロパティインデックスでは対応できません。
そのため、カスタムインデックスが必要になります。
では、カスタムインデックスを作るにはどうすれば良いか?
そこで、datastore-indexes.xmlが出てきます。

上記のqueryに必要なカスタムインデックスを定義したdatastore-indexes.xml








このカスタムインデックスを利用して、上記のqueryは実行されます。
しかし、queryを作る度に、手でこれを書いていたのでは面倒ですし、エラーの原因にもなります。
そのため、GAEには必要なカスタムインデックスを自動で作成する仕組みがあります。
そうして出来上がったのが、datastore-indexes-auto.xmlなのです。
何のqueryも走らせてない状態では空っぽですが、カスタムインデックスが必要なqueryを走らせると自動で作られます。

上記のqueryを走らせた後のdatastore-indexes-auto.xml






デプロイする時に、datastore-indexes-auto.xmlも見てくれるので、datastore-indexes.xmlにコピーしてやる必要はありません。
デプロイが完了すると、管理コンソールで確認することができます。

ただ、反映には少々時間がかかるようで、この画面が表示された後も、すぐには実行できず以下のエラーが出てました。

com.google.appengine.api.datastore.DatastoreNeedIndexException


また、この自動生成が嫌だ!という場合は、datastore-indexes.xmlのautoGenerateをfalseにしてやれば良いです。
datastore-indexes.xml自体が無い場合では、autoGenerate=trueの状態と同じになるので、手でカスタムインデックスを書く気は無い!という場合は、何もしなくても良いということですね。


最後にカスタムインデックスを削除する方法についてです。
queryの変更などでカスタムインデックスを使わなくなった場合、削除してやる必要があります。
http://code.google.com/intl/en/appengine/docs/java/tools/uploadinganapp.html
Deleting Unused Indexesのところに書いてあるコマンドを実行すれば削除されます。

僕の環境だと以下のコマンドになりました。


cd usr\bin\pleiades-e3.5\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.6.0.v201111171704r35\appengine-java-sdk-1.6.0\bin

appcfg.cmd vacuum_indexes D:\usr\var\workspace35\sinsandbox\war

以上でカスタムインデックスのお話はおしまいです。


ただ、上記のようなqueryのためにカスタムインデックスを作るのは課金体系的にも勿体無い気がします。
Slim3にはインメモリのフィルタとソートがあるので、ケースバイケースで使い分けてやる必要があると思います。
例えば、上記の例だと以下のような感じですね。


private TweetMeta t = new TweetMeta();

public List getTweetList() {
return Datastore.query(t).sort(t.memberId.asc).sortInMemory(t.createDate.desc).asList();
}

Datastoreから取得する場合にmemberIdの昇順に並び替えて、取得後にメモリ上でcreateDateの降順に並び替えています。
これならば、Datastoreに指定する条件は1つなので、シングルプロパティインデックスで大丈夫です。

他にもカスタムインデックスを使わずに検索を行うテクニックはたくさんあります。
僕の中ではカスタムインデックスを使うのは、最後の手段だったりw


queryに対する制限なんかはSlim3のサイトを見ることをおすすめします。
クエリとインデックス - Slim3 日本語サイト(非公式)