DataStore は制約や独特の特性があるので、それに適した考え方が必要ですね。
特に書き込みの遅さを回避しつつデータの整合性を取るやり方を目下勉強中です。
webで見つけた資料
「Google App Engine 上でスケールするWebアプリを書く」
Brett Slatkin著、松尾さん訳
http://www.java-users.jp/contents/events/ccc2009spring/materials/A-3-1.pdf
を読んでみたのですが、いくつかわからないことがあります。
Slatkin氏にメールで聞いてみているのですが、お忙しい方らしいのでお返事は
どうかなという雰囲気もあり...、ちょっとこちらでみなさんのお知恵を拝借し
たく思います。
1. ブログを例にした後半部分の30ページで BlogIndex というモデルがコードに
出てきます。でも定義が書かれていません。このロジック部分を知りたいという
のが第一の質問です。(max_index の算出方法とエンティティの持ち方)
30ページのコードはこうなっています:
def post_entry(blogname, title, body):
def txn():
blog_index = BlogIndex.get_by_key_name(blogname)
if blog_index is None:
blog_index = BlogIndex(key_name=blogname)
new_index = blog_index.max_index
blog_index.max_index += 1
blog_index.put()
new_entry = BlogEntry(key_name=blogname + str(new_index),
parent=blog_index,
index=new_index,
title=title, body=body)
new_entry.put()
db.run_in_transaction(txn)
推測するに、構成はGlobalIndex モデルと同一と思います。
class GlobalIndex(db.Model):
max_index = db.IntegerProperty(required=True, default=0)
一方で32ページのページングクエリのコードを見ると:
def get_entries(start_index):
extra = None
if start_index is None:
entries = BlogEntry.gql('ORDER BY index DESC').fetch(POSTS_PER_PAGE + 1)
else:
...
BlogEntry.index は BlogEntry全体でユニークであり、作成順に並ぶ値になるよ
うです。
であれば、30ページの BlogIndex.max_index はどのようなロジックで処理され
て、各エンティティはどのように値を保持し、またどのように更新されていくの
でしょうか。
2. ページングクエリが index のみで行えるとしたら、そもそも BlogEntry の
キーを
key_name=blogname + str(new_index)
とする必要はなく、
key_name=str(new_index)
だけでもいいと思うのですが、どうなのでしょうか。
参考として以下は 31ページ、対になるブログ記事取得コードです。
def get_entry(blogname, index):
entry = BlogEntry.get_by_key_name(
parent=Key.from_path('BlogIndex', blogname),
blogname + str(index))
return entry
3. 上のブログ記事取得コードでは parent を指定していますが、必須でしょう
か。それとも更新系のためでしょうか。もしくは指定することでパフォーマンス
的に有効になるなど、他の理由があるのでしょうか。
2009/11/5 FUJINAKA Tohru <fujinak...@gmail.com>:
blogname 毎にBlogEntryの連番を管理するのが BlogIndex の役目で、エントリ
が追加されるたびに 1 増えるようになっていますね。
>
> 2. ページングクエリが index のみで行えるとしたら、そもそも BlogEntry の
> キーを
> key_name=blogname + str(new_index)
> とする必要はなく、
> key_name=str(new_index)
> だけでもいいと思うのですが、どうなのでしょうか。
>
> 参考として以下は 31ページ、対になるブログ記事取得コードです。
>
> def get_entry(blogname, index):
> entry = BlogEntry.get_by_key_name(
> parent=Key.from_path('BlogIndex', blogname),
> blogname + str(index))
> return entry
確かにそうですね。str(new_index) だけで良いと思います。
>
> 3. 上のブログ記事取得コードでは parent を指定していますが、必須でしょう
> か。それとも更新系のためでしょうか。もしくは指定することでパフォーマンス
> 的に有効になるなど、他の理由があるのでしょうか。
トランザクションのために 各 BlogEntry は BlogIndex の子供になっています。
親を持つ Entity に対しては get_by_key_name に parent を与える必要があり
ます。
Happy coding :-)
--
Takashi Matsuo
Kay's daddy
松尾さん、お返事ありがとうございます。
> blogname 毎にBlogEntryの連番を管理するのが BlogIndex の役目で、エントリ
> が追加されるたびに 1 増えるようになっていますね。
ページング処理を見ると index は全体でユニークな値である必要があるので、
とすると blogname 毎に管理する理由がちょっと解りかねます。
post_entry()でのそうした管理が記事の修正を前提だとしたらなお疑問が増え、
...と、仮に記事修正も post_entry() を通るとすればですが、
・他のエントリと index 値が重なってしまうのでは?
・ページング処理で古い版と新しい版の両方が抽出されてしまうのでは?
うーん、どこかで誤解しているのでしょうか。
前回分の2点については理解できました。
重ねてありがとうございます。
2009/11/5 FUJINAKA Tohru <fujinak...@gmail.com>:
>
> 藤中です。
>
> 松尾さん、お返事ありがとうございます。
>
>> blogname 毎にBlogEntryの連番を管理するのが BlogIndex の役目で、エントリ
>> が追加されるたびに 1 増えるようになっていますね。
>
> ページング処理を見ると index は全体でユニークな値である必要があるので、
> とすると blogname 毎に管理する理由がちょっと解りかねます。
私は Brett じゃないので本当の事はわかりませんが、ページング処理の方が間
違いで、こちらも blogname ごとにフィルターするのが正しいのではないでしょ
うか。私はそう思います。
>
> post_entry()でのそうした管理が記事の修正を前提だとしたらなお疑問が増え、
> ...と、仮に記事修正も post_entry() を通るとすればですが、
> ・他のエントリと index 値が重なってしまうのでは?
> ・ページング処理で古い版と新しい版の両方が抽出されてしまうのでは?
おそらくこのプレゼンで伝えたかった事は、BlogEntry と Comment ではアクセ
スパターンが異なるのでページングの仕方を変えた方が良いという事だと思う
のです。サンプルコードはそれを示すのが目的で、記事の修正の事まで考えた
コードにはなってないと思います。
もちろん現実のアプリでは考える必要がありますが...
Happy coding :-)
--
Takashi Matsuo
Kay's daddy
>
> うーん、どこかで誤解しているのでしょうか。
>
> 前回分の2点については理解できました。
> 重ねてありがとうございます。
松尾さん、お返事ありがとうございます。
まだSlatkin氏からの返事はありませんが、おかげでだいぶ落ち着きました。
もしや何かマジカルな処理がイースターエッグのように隠されているのかとも思っ
ていたのですが、どうやらそうではないようですね。
どうもありがとうございました。