Datastore を理解する
目次
Datastoreを使った開発をするにあたって、Datastoreを理解するためのメモです。
随時更新します。
RDB との比較
概念 | Datastore | RDB |
---|---|---|
カテゴリ | Kind | Table |
1つのオブジェクト | Entity | Row |
各データ | Property | Field |
ユニークなID | Key | Primary Key |
Kind -> Entity -> Propertyという親子関係のような感じ。
データ整理
Google Cloud Datastoreでのデータ整理の考え方
Google Cloud Datastore のような非リレーショナル データベースにおけるデータのモデリングや保存には、固有の難しさがあります。結合や正規化など、リレーショナル データベースの有益な機能の多くは、非リレーショナル データについては、スケーラビリティに欠けるという理由で適用されません。リレーショナル データベースを「オブジェクトと関係」としてとらえるという一般的なアプローチも、非リレーショナル データベースに当てはめるのは困難です。
次の例でデータをパスとして整理する方法を考える
例 : マルチユーザーブログ
RDBの場合
User
id | username | name |
---|---|---|
1 | tonystark | Tony Stark |
2 | dianaprince | Diana Prince |
Post
id | user_id | content |
---|---|---|
1 | 1 | Hello, world! |
2 | 2 | Another post |
特定のユーザが書き込んだすべての投稿を検索したい場合
SELECT * FROM Posts WHERE user_id = {user_id}
でOK
Datastore の場合
User と Post の2つの Kind を持つようにすると、次のようになる。
Key | Data |
---|---|
(Post, 1) | {“user”: Key(User, tonystark), “content”: “Hello, World!”} |
(Post, 2) | {“user”: Key(User, dianaprince), “content”: “Another post”} |
(User, tonystark) | {“name”: “Tony Stark”} |
(User, dianaprince) | {“name”: “Diana Prince”} |
Post Kind 全体を username でフィルタリングすることで、特定のユーザーが書き込んだ全ての投稿を検索できる。
datastore.Query(kind='Post', filters=[('user', '=', Key('User', username))])
このクエリは結果整合性をもつ。
ファイルシステム
非リレーショナルデータをテーブルやキーの観点からではなく、ファイルシステムとして考える
/1.post
/2.post
/tonystark.user
/dianaprince.user
このデータは、ユーザー別にグループ化して再整理できる
/tonystark.user
/1.post
/dianaprince.user
/2.post
Key | Data |
---|---|
(User, tonystark) | {“name”: “Tony Stark”} |
(User, tonystark, Post, 1) | {“content”: “Hello, World!”} |
(User, dianaprince) | {“name”: “Diana Prince”} |
(User, dianaprince, Post, 2) | {“content”: “Another post”} |
投稿をユーザー別に整理すると、エンティティ グループが作成されます。その中にはユーザーのプロフィールとすべての投稿が含まれます。Cloud Datastore では、1つのエンティティ グループに対するクエリは強い整合性を持ちます。このため、ユーザーは投稿を作成すると、すぐに見ることができます。祖先をキーに指定してクエリを行うことも可能です。
datastore.Query(kind='Post', ancestor=Key('User', username))
ユーザーのプロフィールと投稿を 1 つのエンティティグループにまとめると、整合性と書き込みスループットがトレードオフになる。
エンティティグループ
エンティティグループは、1 つのルートエンティティと、その子エンティティやそれを継承するエンティティから構成される階層。
エンティティグループを作成するには、祖先パス、つまり子キーの前に一連の親キーをつなげて指定する。 (https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore?hl=ja#h.3loc7ynqbw6i)
この図では、キー「ateam」を持つルートエンティティには、キー「ateam/098745」とキー「ateam/098746」を持つ 2つの子エンティティがある。
エンティティグループ内では、次の特性が保証される。 - 強整合性 - トランザクション性 - ローカル性
エンティティグループと祖先クエリの制限
エンティティグループと祖先クエリを使用する方法は、次の2つの問題がある
- 各エンティティ グループの書き込みは、1秒間に1回の更新
- エンティティの作成後にエンティティグループの関係を変更できない