GAEの有償版とDataStoreの制限

閲覧: 260 回
最初の未読メッセージにスキップ

Sumio Ebisawa

未読、
2009/06/22 21:25:012009/06/22
To: Google-App-Engine-Japan
Google App Engineを使ってコミュニティサイトの構築を考えておりますが、DataStoreへのクエリーで一度に取得できるエンティ
ティ数が1000件まで、というのが気になります。

http://groups.google.co.jp/group/google-app-engine-japan/browse_thread/thread/28207f93c7f5b8ed
上記のような回避方法があるのは知っておりますが、なにぶんPython初心者のため、できるだけコーディングをシンプルに行いたいのが本音です。

そこで、有償版のGoogleAppEngineではどうなのか、と思って調べたのですが、、ピンポイントに「DataStoreの1000件の制限が
なくなる」という表現が見つかりませんでした。(探し方が悪いかもしれませんが)
http://code.google.com/intl/ja/appengine/docs/billing.html
http://googleappengine.blogspot.com/2009/02/new-grow-your-app-beyond-free-quotas.html

もし、ご存じの方や有償版をお使いの方がいらっしゃれば、アドバイスをお願いいたします。

Takashi Matsuo

未読、
2009/06/22 21:43:052009/06/22
To: google-app-...@googlegroups.com
松尾です。

2009/6/23 Sumio Ebisawa <sebisawa...@gmail.com>

私の知る限り有償版にしてもこの制限値は増えません。

1000件を超えてエンティティを取得したい、その目的はなんでしょうか。目的
がきちんとページングしたいということなら、こちらの pager.py が使えそう
です。

http://bitbucket.org/moraes/appengine/src/tip/gaefy/db/pager.py

1000件を超えたエンティティに対して何らかの処理をしたいという事であれば
新しく出た Task Queue API の使用を検討するのが良いと思います。

Happy coding :-)

-- Takashi Matsuo

Sumio Ebisawa

未読、
2009/06/23 12:51:002009/06/23
To: Google-App-Engine-Japan
松尾様


返信ありがとうございます。

今考えているのは、約1万人が会員登録されているサイトで、各会員のサイト
利用状況を集計して出力する、というものです。別にリアルタイムで計算する
必要はないので、1時間に1回のバッチで更新されればよいのですが。

> 1000件を超えたエンティティに対して何らかの処理をしたいという事であれば
> 新しく出た Task Queue API の使用を検討するのが良いと思います。

Task Queue APIではDataStoreの1000件の制限がなくなるのでしょうか?
下記でそういった記述が見つからないようなので、その出典か実験結果を
教えていただけますでしょうか?

http://googleappengine.blogspot.com/2009/06/new-task-queue-api-on-google-app-engine.html
http://code.google.com/intl/ja/appengine/docs/python/taskqueue/overview.html#Quotas_and_Limits

あと、質問ばかりで恐縮ですが、Task Queue APIとCronの違いを
教えていただけると幸いです。(必要なら別のスレッドを立てます)

atusi nakamura

未読、
2009/06/23 13:23:082009/06/23
To: google-app-...@googlegroups.com
a2cです。

わたしも1000件以上使えればいいのにと思っている派です。色々めんどくさいですよね。

まず、1000件の制限は、何をやっても無くならないと思っていた方がいいかとおもいます。
もし1000件以上扱えたとしても、すぐに30秒の制限に引っかかってしまいます。
(ローカルでは動くのに、本番環境では動かない事は良くあること>処理速度の問題)

そんな時には、tmatsuoさんの仰るとおり、Pagingするか、CronやTaskQueueを利用するかだと思います。

Cronは、処理すべき対象があろうが無かろうが言われた時間に決まった処理をする。
TaskQは、処理すべき対象が積んであれば処理をして、無ければ何もしない。

こんな感じでしょうか。まだ、TaskQでの実装をしていませんがドキュメントを読む限りそんな感じです。
(時間あたりの処理回数は多そうですね。"task object size"が取り扱えるデータ量だとすると、少な過ぎる気がします。)

> 1時間に1回のバッチで更新されればよいのですが。

と言うことであれば、Cronを使うのが本来の目的に合っているかと思います。
--
a2c
unemployed



2009/06/24 1:51 に Sumio Ebisawa<sebisawa...@gmail.com> さんは書きました:

Hiroaki Kawai

未読、
2009/06/23 22:21:552009/06/23
To: google-app-...@googlegroups.com
川井です。

これはかなり反則的な処理の仕方なので、広めていいのかどうかよくわかりませんが、
1. db.GqQuery("SELECT __key__ FROM Hoge ORDER BY __key__") で一覧を取得
2. リダイレクションを使って、iterator 相当の動作をするようにする。
3. このとき Hoge.get(dbkey) で一件取得し、そのエンティティのみ処理するようにする。
4. wget --max-redirect 100000 http://appid.appspot.com/...
を組み合わせてバッチ処理をしていいます。こうすると処理途中で止めることもできます。

1000 件以上使えるようにするのは...仮に単純にできるようになったとしても、
遅いので役には立たないでしょう。

また Cron Task にしたところで、1000 件の制限が消えることはありません。

今回のケースでは、Cron + task queue の併用をするのがいいと思います。


2009/06/24 2:23 に atusi nakamura<a2c...@gmail.com> さんは書きました:

Ian Lewis

未読、
2009/06/24 0:45:322009/06/24
To: google-app-...@googlegroups.com
川井さん、

イアンと申します。

この方法はなかなかいいと思います。でも、やっぱりエンティティを一リクエスト一個だけを処理するのがもったいないと思います。なぜなら、リクエストのCPUとネットワークオーバーヘッドがかかりますし、その分お金がかかりそうです。処理がそんなに重くなければ、下記と同じ方法で一リクエスト数百件を処理するのができると思います。Transactionでやると途中で止めることもできると思います。(ちなみにバッチ処理の場合、remote apiもありと思います)

えびさわさん、

ユーザのアクションによって、データを処理しないといけない場合は、task queue APIを使いこなせば、かなりいいと私も思います。

2009/6/24 Hiroaki Kawai <hiroak...@gmail.com>



--
=======================================
株式会社ビープラウド  イアン・ルイス
〒150-0012
東京都渋谷区広尾1-11-2アイオス広尾ビル604
email: ianm...@beproud.jp
TEL:03-5795-2707
FAX:03-5795-2708
http://www.beproud.jp/
=======================================

Sumio Ebisawa

未読、
2009/06/24 11:11:162009/06/24
To: Google-App-Engine-Japan
海老澤です。皆様、アドバイスありがとうございます。


Task Queue APIのドキュメントを何度となく読んで、Cronとは目的が異なる
ものだとわかってきました。

Task Queue API
- アプリ実行時にバックエンドで処理を走らせるもの
- その目的は、重い処理の完了を待たずにユーザにレスポンスを返すこと
Cron
- ユーザからのアクセスがなくても、定期的にアプリを実行させる手段

さて、下記のブログに、こんな例が出ています。
http://googleappengine.blogspot.com/2009/06/new-task-queue-api-on-google-app-engine.html

==================================================================
# for each user, add a task to send a custom email message
for u in users:
taskqueue.add(url='/work/sendmail',
params=dict(to=u.email, subject='Hello ' + u.name, body='this
is a message!'))

return # finished now, emails will be sent offline when tasks execute

※※※後略※※※
==================================================================

もし「users」に20000件のメールアドレスが登録されていたら、どうなるのでしょうか?

1)1000人分のユーザしかメールが送信されない
2)10000人分のユーザしかメールが送信されない(1日に)
3)全員にメールが届く

なぜ2番の選択肢が出てきたかというと、TaskQueueのドキュメントで
「task insertions per day」が一日10000件まで、とあるからです。
http://code.google.com/intl/ja/appengine/docs/python/taskqueue/overview.html#Quotas_and_Limits

※実際に試したほうが早いかな?

Hiroaki Kawai

未読、
2009/06/24 12:34:312009/06/24
To: google-app-...@googlegroups.com
川井です。

このプログラムのままであれば、2 が正解でしょう。
しかも、途中で taskqueue.add のところで Exception が飛ぶんじゃないでしょうか。

会員が 20000 人いるのであれば、「全タスクを 10000 個以下のタスクに分割する。
ただしひとつのタスクは 1 リクエストレスポンスで終わる程度におさめる」
という手がありますが、別の手として「Google に Quota をあげてもらう」という手もあるかもしれません。:-p
task queue を最大限に使い切ると、10 parallel で平均 1000 回繰り返すので、ひとつのタスクが 30 秒程度の
処理だったとすると、8 時間まわりっぱなしになります。

と、ここまで書いてから改めて話の流れを見直したのですが、1000 件の制限というのは、
db.GqlQuery.fetch() / db.Query.fetch() の制限を指していますよね。
fetch() は、エンティティとして全てのプロパティが揃った状態のデータを準備するので
処理負荷を鑑みて 1000 件の制約が入っていると推測しています。

フルセットのエンティティ 1000 件を毎回メモリにロードしないと処理できない、というのは
ちょっと…頭を冷やして…なんとかしてください、というところなのでしょう。

fetch() を使わないのであれば、1000 件の制約は特にないはず。
全てのプロパティが揃っていなくてもいいのであれば、「インデックス」と「キー」だけで計算するのが効率がよくて、
実際 "SELECT __key__ FROM Hoge WHERE ...." というクエリで 2500 件ぐらいの key を
取り出したりしていました(この処理自体ではエンティティを生成していません)。
# 後はこのキー一覧をプログラムに埋め込んでしまうなり、str() にしてから memcache に
# json.write() してしまうなりすると、処理効率がいいです。
task queue に突っ込むには key だけでいいはずなので、こんなやり方が向いていると個人的には思っています。
http://code.google.com/intl/ja/appengine/docs/python/datastore/queriesandindexes.html#Queries_on_Keys

いずれにせよ、もしよろしければ実際にやった結果を教えていただけると、ありがたいです。

Sumio Ebisawa

未読、
2009/06/24 19:45:012009/06/24
To: Google-App-Engine-Japan
海老澤です。返信ありがとうございます。


> と、ここまで書いてから改めて話の流れを見直したのですが、1000 件の制限というのは、
> db.GqlQuery.fetch() / db.Query.fetch() の制限を指していますよね。

すみません、その辺がよくわかってないです。下記には「クエリの最大結果オフセット」が
1000件とあるだけなので、「SELECT __key__ ..」なら無制限ということを知りませんでした。
http://code.google.com/intl/ja/appengine/docs/python/datastore/overview.html#Quotas_and_Limits

おっしゃる通り、20000件のレコードが処理できればいいだけで、一度に20000件のエンティティを
生成する必要なんてありません。

> いずれにせよ、もしよろしければ実際にやった結果を教えていただけると、ありがたいです。

すみません、まだGAEで構築するかどうかを決めるための情報収集の段階で、あまり
複雑な検証ができない状態です。(ローカルの開発環境をいじっている程度)。

実データをGAEに入れて回すことができれば、より具体性のある結果を提示できるのです
が・・・。

Sumio Ebisawa

未読、
2009/06/27 11:45:192009/06/27
To: Google-App-Engine-Japan
追記です。

remote_apiの解説ページでこんな記述を見つけました。

If you don't know how many entities you will want, you can use the
__key__ pseudo-property to efficiently iterate over large result sets.
This also allows you to avoid the 1000 entity limit imposed on normal
datastore queries:

要約:keyのプロパティで効果的なイテレーションを行えば1000件の制限を回避することができる。

掲示しているサンプルスクリプト
==================================================================
entities = MyModel.all().fetch(100)
while entities:
for entity in entities:
# Do something with entity
entities = MyModel.all().filter('__key__ >', entities[-1].key
()).fetch(100)
==================================================================

最初に100件取得し、それの処理が終わったら次の100件を取得する、ということだと思います。
全員に返信
投稿者に返信
転送
新着メール 0 件