Datastoreでのデータモデル設計メモ

最終更新日 : 2010/12/13 (2010/12/13 より執筆開始)
下滝 亜里 <asatohan at gmail.com>
内容に関するコメント(感想、提案、書き間違いの指摘)は歓迎します。

このドキュメントの内容は、まずはブログで書いています
ドラフトバージョン


はじめに

個人的に趣味で、Google App Engine/Java(実際はScalaを使用)を使い始めて一年ぐらいになります。そこで、このドキュメントでは、Datastoreのこれまでに設計したデータモデルについて少しふりかえりながら、以下を紹介します。 なお、基本的には、JDOを使用し、一部でObjectifyを使ってます。

Webサイトの事例

事例として作ってるWebサイトはGoodsHomeというものです。もともとは、新刊の定期自動チェックのために作ってました。今は、モノ(商品)を中心としてファンやユーザーがつながれるようなソーシャルなサイトにしようと思ってます。

執筆時点で、47のKindを定義しています。

データモデル設計の事例

事例1

この事例では、NewItemというモデルを検討します。このモデルは、商品が新たに見つかった時の情報を表します。新たな商品データがあるかどうかは、タスクを使って定期チェックされます。なお、150,000以上のエンティティがあります。

図のPKは、プライマリキーのことです。PKの値はasinで、これは、amazonの商品IDです。categoryは、商品のカテゴリ(書籍やおもちゃなど)を表しています。dateは、見つかった日時を表します。ReadOnlyは、そのプロパティが読み取りのみ行われることを示します。

このモデルに対する操作は、二つです。

特徴は以下です。

最後に、下記の図は、上記のようなモデルをより一般的に表したものです。

事例2

この事例ではWishTagというモデルを検討します。このモデルは、ある商品を欲しいと思ったユーザー数(正確には思った回数)を表します。facebookの「イイネ!」ボタンと同じような機能です。ユーザーが「欲しい!」ボタンをクリックすると、カウントが一つ増えます。ちなみに、現状、1,800程度のエンティティがあります。

プライマリキーは、asin(amazonの商品ID)です。countはクリック数を表します。

このモデルに対する操作は、三つです。

特徴は以下です。 下記の図は、上記のようなモデルをより一般的に表したものです。

設計上の悩み

設計上の悩みは、どのユーザー(ユーザー登録している者としていない者)がいつクリックしたのかを示す情報がないことです。つまりこのような情報を保存するような仕様への変更が出た時、データモデルをどう変更するのか? を考える必要があります。新たなKindを定義することなく、単にプロパティを追加するような変更では対応できないと考えます。

事例3

この事例では、商品のブックマークを表すモデルを検討します。各ユーザーは、商品IDをもとに、その商品をブックマークできます。このモデルは、Datastoreに慣れていない初期に作ったモデルです。

BookmarksとBookmarkの二つのクラス(Kind)を定義しました(JDOを使用)。Bookmarkは、各商品を対象としたブックマークを表します。asinは、amazonの商品IDです。userIdは、ブックマークしたユーザのIDを表します。Bookmarksは、単にuserIdごとに、Bookmarkの一覧を保持するだけのものです。

なお、JDOを使用しているので上記のようにモデルを表していますが、Datastore上では、実際には、以下のようにデータが保存されますので注意してください(詳しくはGAEのドキュメントを参照)。

このモデルに対する操作は、三つです。

特徴は以下です。 下記の図は、上記のようなモデルをより一般的に表したものです。

設計上の悩み

設計上失敗していると感じるのは、Bookmarksがなぜ必要なのか、という点です。不要な理由はあります。

-性能上の欠点: ブックマークの追加や削除が行われるとindexのプロパティ値の更新が発生する

そもそも、なぜ現状のようなモデル設計になっているかというと、不慣れだったこともありますが、ユーザーIDをもとにブックマークの一覧どのように保持・取得するかという観点から、現状のモデルを思いついた(それ以外は思いつけなかった)ということがあります。

実は、現状のモデルはバージョン2で、バージョン1では、BookmarkはuserIdを保持していませんでした。変更した理由は、性能上の理由と言うよりは、クエリの行いやすさの理由だった気がします。あるユーザーがその商品をブックマークしているかどうかを userId == '%s' && asin == '%s' のようにクエリできるようにしたかったからです。

ちなみに次のバージョンでは、Bookmarksを削除する予定です。それと、ブックマークした日時を保存するプロパティの追加も検討しています。

事例4

この事例のモデルは、タグです。単に商品にタグを付けれる機能です。各商品に対してタグは10つまで付けられる仕様です。JDO使用です。

TagsとTagの二つのクラス(Kind)があります。Tagsは、ある商品に付けられたタグの一覧を保持するだけのものです。asinはamazonの商品IDを表します。Tagは個々のタグを表します。nameは、タグ名を、userIdは、このタグを付けたユーザーのIDを(ない場合もある)、dateはタグが付けられた日時を表します。

このモデルに対する操作は、以下です。

特徴は以下です。

下記の図は、上記のようなモデルをより一般的に表したものです。

データモデル設計の考慮点

今回のモデルに限りませんが、設計する上で考慮の必要性が高いように思える順番は以下です。

付録:データモデルのパターン

付録:データモデルの進化パターン

参考文献とリソース

更新履歴

todo/memo

  • Low-level APIレベルでのデータストアの理解は必須 -> JDOレベルで誤解に基づいた設計をしてしまう可能性がある。