Lucene on Google App Engineの性能評価

Google App Engineでluceneを使ってN-gram全文検索を行ってみるの続きです。

というわけで、簡単ながら試験的に性能評価を行ってみました。

pythonのtimeitを使って5回繰り返して最小値を取ってみました。繰り返しているので、スピンアップされた状態となると思います。
具体的には以下のスクリプトを使いました。

URL = "http://all-write.appspot.com/api/search?email=mail&auth=" + TOKEN
def test():
  f = urllib.urlopen(URL + "&q=なるほど")

if __name__=='__main__':
  from timeit import Timer
  t = Timer("test()", "from __main__ import test")
  print min(t.repeat(3, 1))

入れたドキュメントは手近にあったAndroidの日本語メーリングリストで、4000通、約16MBです。一つのドキュメントにそれなりの量の文章が入っているものとみていいと思います。
4000のドキュメントを入れた段階で、indexを持つエンティティが43個できあがりました。

以下にsearchを行った際に返ってくるまでの秒数を記します。数字はドキュメント数です。

なお、pingで得られたRTTは平均44msでした。

ドキュメント数 msec index entityの数
トップページ(静的)の取得 0.31 -
1 0.41 1
10 0.51 1
50 0.61 1
100 0.61 1
110 0.68 2
200 0.92 3
500 1.74 6
1000 2.72 12
2000 4.09 23
3000 5.52 36
4000 8.19 43

うーん、4000ドキュメントで8秒はまずいだろう。というわけで、ボトルネックを探してみました。

処理名 msec
User情報の取得 77
Indexの取得 5641
index readerの生成 535
search終了 10
doc取得 2
Noteの生成 145

というわけで、Indexの取得に凄まじく時間がかかっていることが分かりました。検索自体は10msecぐらいしかかかってないので、Luceneは悪くないよ!

ちょっと調べると、これはDatastoreを理解してなくて、普通にqueryをかけていたからだということが分かったので、keyのリストを元にバッチgetをするようにしたところ、

個数 秒数
4000 5.78

ちょっと高速化しました。

また、Indexの数自体も減らすことを考えました。Indexのサイズをできるだけ抑えるために、今まではテキストデータもindexの中に入れていたのをstore.NOにして入れないようにしました。実際のデータはDatastoreの中にあるので必要ないはずです。

ところで、今回はメールというばらつきが非常に大きいドキュメントを使ったために、1MBを超えないようにIndexを順番に作成していくと、個々のIndexに空きができてしまっています。これは例えば140文字とかであればもっと詰めることが可能なはずです。ちょうど当てはまりそうな残り容量があるIndex Entityを探すのが本流なのかもしれませんけど…

というわけで、上記のIndexのサイズ抑制およびバッチ処理のコードを加え、UTF-8で140文字のエントリを入れてみました。

すると、

エントリの個数 秒数 Index Entityの数
4000 2.32 13

となりました。ドキュメントサイズが違うため単純に比較はできませんが、ネットワークの遅延があるとはいえやはり遅いですね。まあ、これで十分な用途もあるかもしれません。

しかし、simplenoteはどうやってるんでしょうねぇ。

ソースコード

いろいろ途中ですがgithubで公開してみます。

http://github.com/shirou/all-write

NoteServiceSearchServiceなどがなにかの参考になるかもしれません。